Проблема с картой C++ с использованием указателей функций-членов в качестве ключей

Я пишу на C++, пытаюсь скомпилировать под Ubuntu, и у меня возникают некоторые проблемы с картой, использующей указатели функций в качестве ключей. Когда я определяю карту, я не получаю ошибок компиляции, но как только я пытаюсь вставить элемент, я получаю довольно многословное

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<’

Вот пример, вызвавший указанное выше сообщение об ошибке:

#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;
}

В чем может быть проблема? Я пробовал как с вставкой, так и с [] assign, и получаю ту же ошибку. Просматривая форумы, я нашел это; но может быть дело в этом? Я не думаю, что мне нужно определять оператор «‹» для указателей на функции (разве они не должны вести себя как обычные указатели?) ... или мне нужно?


person Alberto    schedule 13.02.2014    source источник
comment
Аналогично: stackoverflow. ком/вопросы/11983070/   -  person Matteo Italia    schedule 13.02.2014
comment
Не просто похоже, я бы назвал это дубликатом....   -  person Mats Petersson    schedule 13.02.2014
comment
@MatsPetersson: да, изначально я думал, что речь идет об обычных указателях на функции (в отличие от указателей на функции-члены); голосование за закрытие как дубликат.   -  person Matteo Italia    schedule 13.02.2014
comment
См. также: stackoverflow.com/q/21696881/1782465   -  person Angew is no longer proud of SO    schedule 13.02.2014


Ответы (2)


Ошибка говорит вам все, что вам нужно знать:

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

Вы не можете сравнивать указатели на функции-члены, используя стандартный operator<, поэтому вы должны указать собственный компаратор при объявлении вашей карты.

К сожалению, указатели на функции-члены нельзя сравнивать на предмет неравенства, поэтому в этом случае нельзя определить оператор сравнения или использовать std::map. Я предлагаю использовать std::unordered_map, который требует только сравнения std::hash и равенства, что вы можете сделать. См. здесь для хеширования и здесь для сравнение равенства.

person rubenvb    schedule 13.02.2014
comment
Технически их можно сравнивать по неравенству (!=), но не упорядочивать (< и подобные). - person Angew is no longer proud of SO; 13.02.2014

Вы можете реализовать специализацию шаблона для less‹ int (MyClass::* const)() >, как показано ниже:

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;
        }
    };
}

Могут быть лучшие способы сравнения указателей на члены, чем «приведение» их к целым числам, что является хаком, зависящим от реализации, в соответствии с этот вопрос. Эти вопросы содержат подробную информацию о том, как это сделать тот.

person Martin J.    schedule 13.02.2014
comment
В лучшем случае это неопределенное поведение. - person rubenvb; 13.02.2014
comment
Ну да, это действительно взлом - person Martin J.; 13.02.2014