0

I am writing in C++, trying to compile under Ubuntu, and I am experiencing some issues with a map using function pointers as keys. When I define the map, I get no compiling errors, but as soon as I try to insert an element, I get a rather wordy

In file included from /usr/include/c++/4.6/string:50:0, from /usr/include/c++/4.6/bits/locale_classes.h:42, from /usr/include/c++/4.6/bits/ios_base.h:43, from /usr/include/c++/4.6/ios:43, from /usr/include/c++/4.6/ostream:40, from /usr/include/c++/4.6/iostream:40, from main.cpp:1: /usr/include/c++/4.6/bits/stl_function.h: In member function ‘bool std::less<_Tp>::operator()(const _Tp&, const _Tp&) const [with _Tp = int (MyClass::*)()]’: /usr/include/c++/4.6/bits/stl_tree.h:1277:4: instantiated from ‘std::pair<std::_Rb_tree_iterator<_Val>, bool> std::_Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::_M_insert_unique(const _Val&) [with _Key = int (MyClass::*)(), _Val = std::pair<int (MyClass::* const)(), std::vector<int> >, _KeyOfValue = std::_Select1st<std::pair<int (MyClass::* const)(), std::vector<int> > >, _Compare = std::less<int (MyClass::*)()>, _Alloc = std::allocator<std::pair<int (MyClass::* const)(), std::vector<int> > >]’ /usr/include/c++/4.6/bits/stl_map.h:518:41: instantiated from ‘std::pair<typename std::_Rb_tree<_Key, std::pair<const _Key, _Tp>, std::_Select1st<std::pair<const _Key, _Tp> >, _Compare, typename _Alloc::rebind<std::map<_Key, _Tp, _Compare, _Alloc>::value_type>::other>::iterator, bool> std::map<_Key, _Tp, _Compare, _Alloc>::insert(const value_type&) [with _Key = int (MyClass::*)(), _Tp = std::vector<int>, _Compare = std::less<int (MyClass::*)()>, _Alloc = std::allocator<std::pair<int (MyClass::* const)(), std::vector<int> > >, typename std::_Rb_tree<_Key, std::pair<const _Key, _Tp>, std::_Select1st<std::pair<const _Key, _Tp> >, _Compare, typename _Alloc::rebind<std::map<_Key, _Tp, _Compare, _Alloc>::value_type>::other>::iterator = std::_Rb_tree_iterator<std::pair<int (MyClass::* const)(), std::vector<int> > >, std::map<_Key, _Tp, _Compare, _Alloc>::value_type = std::pair<int (MyClass::* const)(), std::vector<int> >]’ main.cpp:36:51: instantiated from here /usr/include/c++/4.6/bits/stl_function.h:236:22: error: invalid operands of types ‘int (MyClass::* const)()’ and ‘int (MyClass::* const)()’ to binary ‘operator<’ 

Here is the example that caused the above error message:

#include <iostream> #include <map> #include <vector> // class definition class MyClass { public: int f1(void); int f2(void); }; int MyClass::f1(void) { return 1; } int MyClass::f2(void) { return 2; } using namespace std; int main( int argc, char* argv[] ) { // define map map< int (MyClass::*)(void), vector<int> > myMap; vector<int> myVector; //myMap[ &MyClass::f1 ] = myVector; myMap.insert( make_pair( &MyClass::f1, myVector) ); return 0; } 

What could be the issue? I tried with both insert and [] assign, and I get the same error. Browsing the forums, I found this; but could that be the issue? I don't think I need to define an operator "<" for function pointers (shouldn't they behave as regular pointers?) ...or do I?

4

2 Answers 2

2

The error is telling you all you need to know:

invalid operands of types ‘int (MyClass::* const)()’ and ‘int (MyClass::* const)()’ to binary ‘operator<’ 

You cannot compare member function pointers using standard operator<, so you must provide a custom comparator when declaring your map.

Unfortunately, pointers to member functions cannot be compared for inequality, so you cannot define a comparison operator or use a std::mapin this case. I suggest using std::unordered_map, which only needs a std::hash and equality comparison, which you can do. See here for hashing and here for equality comparison.

Sign up to request clarification or add additional context in comments.

1 Comment

Technically, they can be compared for inequality (!=), but not ordered (< and similar).
-1

You could implement the template specialization for less< int (MyClass::* const)() >, like follows:

typedef int (MyClass::*tMyClassMember)(); namespace std { template<> struct less<tMyClassMember> { bool operator()(const tMyClassMember& k1, const tMyClassMember& k2) const { auto p1 = reinterpret_cast<const intptr_t*>(&k1); auto p2 = reinterpret_cast<const intptr_t*>(&k2); return *p1 < *p2; } }; } 

There may be better ways to compare pointer-to-members than "casting" them to integers, which is an implementation-specific hack, according to this question. That questions contains details about how to do that.

2 Comments

This is undefined behavior, at best.
Well yeah, it's really a hack

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.