c++c++11visual-studio-2013std-functionboost-function

using std::function in a std::map


I have a class...

#include <map>
#include <boost/function.hpp>

enum class ECmd { one, two, three };

class C
{
public:

    void Command(ECmd e)
    {
        auto pos = m_fnCmd.find(e);

        if (pos != m_fnCmd.end())
        {
            // call the function
            (pos->second)(this);
         }
        else
        {
            printf("no command!\n");
        }
    }

protected:
    using fnCmd = boost::function<void(C*)>;
    using fnCmdMap = std::map<ECmd, fnCmd>;

    static const fnCmdMap m_fnCmd;

    // the command functions
    void One() { printf("one.\n"); }
    void Two() { printf("Two.\n"); }
    void Three() { printf("Three.\n"); }
};

const C::fnCmdMap C::m_fnCmd =
{
    {std::make_pair(ECmd::one, &C::One)},
    {std::make_pair(ECmd::two, &C::Two)},
    {std::make_pair(ECmd::three, &C::Three)},
};

Which demonstrates a technique i use for processing id based commands. This code works just fine, however when i change the class to use std::function instead of boost::function it fails to compile - does not like initializing C::m_fnCmd.

The error message is:

1>c:\program files (x86)\microsoft visual studio 12.0\vc\include\functional(506): error C2664: 'void std::_Func_class<_Ret,C *>::_Set(std::_Func_base<_Ret,C *> *)' : cannot convert argument 1 from '_Myimpl *' to 'std::_Func_base<_Ret,C *> *'
1>          with
1>          [
1>              _Ret=void
1>          ]
1>          Types pointed to are unrelated; conversion requires reinterpret_cast, C-style cast or function-style cast
1>          c:\program files (x86)\microsoft visual studio 12.0\vc\include\functional(442) : see reference to function template instantiation 'void std::_Func_class<_Ret,C *>::_Do_alloc<_Myimpl,_Fret(__thiscall C::* const &)(void),_Alloc>(_Fty,_Alloc)' being compiled
1>          with
1>          [
1>              _Ret=void
1>  ,            _Fret=void
1>  ,            _Alloc=std::allocator<std::_Func_class<void,C *>>
1>  ,            _Fty=void (__thiscall C::* const &)(void)
1>          ]
1>          c:\program files (x86)\microsoft visual studio 12.0\vc\include\functional(442) : see reference to function template instantiation 'void std::_Func_class<_Ret,C *>::_Do_alloc<_Myimpl,_Fret(__thiscall C::* const &)(void),_Alloc>(_Fty,_Alloc)' being compiled
1>          with
1>          [
1>              _Ret=void
1>  ,            _Fret=void
1>  ,            _Alloc=std::allocator<std::_Func_class<void,C *>>
1>  ,            _Fty=void (__thiscall C::* const &)(void)
1>          ]
1>          c:\program files (x86)\microsoft visual studio 12.0\vc\include\functional(442) : see reference to function template instantiation 'void std::_Func_class<_Ret,C *>::_Reset_alloc<_Fret,C,,std::allocator<std::_Func_class<_Ret,C *>>>(_Fret (__thiscall C::* const )(void),_Alloc)' being compiled
1>          with
1>          [
1>              _Ret=void
1>  ,            _Fret=void
1>  ,            _Alloc=std::allocator<std::_Func_class<void,C *>>
1>          ]
1>          c:\program files (x86)\microsoft visual studio 12.0\vc\include\functional(442) : see reference to function template instantiation 'void std::_Func_class<_Ret,C *>::_Reset_alloc<_Fret,C,,std::allocator<std::_Func_class<_Ret,C *>>>(_Fret (__thiscall C::* const )(void),_Alloc)' being compiled
1>          with
1>          [
1>              _Ret=void
1>  ,            _Fret=void
1>  ,            _Alloc=std::allocator<std::_Func_class<void,C *>>
1>          ]
1>          c:\program files (x86)\microsoft visual studio 12.0\vc\include\functional(671) : see reference to function template instantiation 'void std::_Func_class<_Ret,C *>::_Reset<void,C,>(_Fret (__thiscall C::* const )(void))' being compiled
1>          with
1>          [
1>              _Ret=void
1>  ,            _Fret=void
1>          ]
1>          c:\program files (x86)\microsoft visual studio 12.0\vc\include\functional(671) : see reference to function template instantiation 'void std::_Func_class<_Ret,C *>::_Reset<void,C,>(_Fret (__thiscall C::* const )(void))' being compiled
1>          with
1>          [
1>              _Ret=void
1>  ,            _Fret=void
1>          ]
1>          c:\program files (x86)\microsoft visual studio 12.0\vc\include\utility(157) : see reference to function template instantiation 'std::function<void (C *)>::function<_From>(_Fx &&)' being compiled
1>          with
1>          [
1>              _From=void (__thiscall C::* )(void)
1>  ,            _Fx=void (__thiscall C::* )(void)
1>          ]
1>          c:\program files (x86)\microsoft visual studio 12.0\vc\include\utility(157) : see reference to function template instantiation 'std::function<void (C *)>::function<_From>(_Fx &&)' being compiled
1>          with
1>          [
1>              _From=void (__thiscall C::* )(void)
1>  ,            _Fx=void (__thiscall C::* )(void)
1>          ]
1>          c:\projects\test\fntest\fntest.cpp(60) : see reference to function template instantiation 'std::pair<const _Kty,_Ty>::pair<ECmd,void(__thiscall C::* )(void),void>(std::pair<ECmd,void (__thiscall C::* )(void)> &&)' being compiled
1>          with
1>          [
1>              _Kty=ECmd
1>  ,            _Ty=C::fnCmd
1>          ]
1>          c:\projects\test\fntest\fntest.cpp(60) : see reference to function template instantiation 'std::pair<const _Kty,_Ty>::pair<ECmd,void(__thiscall C::* )(void),void>(std::pair<ECmd,void (__thiscall C::* )(void)> &&)' being compiled
1>          with
1>          [
1>              _Kty=ECmd
1>  ,            _Ty=C::fnCmd
1>          ]
1>

Solution

  • It works with GCC and Clang (see Jonathan's comment). To make it work in VS2013, you can add std::mem_fn() around the pointers to the member functions:

    const C::fnCmdMap C::m_fnCmd =
    {
        {std::make_pair(ECmd::one, std::mem_fn(&C::One))},
        {std::make_pair(ECmd::two, std::mem_fn(&C::Two))},
        {std::make_pair(ECmd::three, std::mem_fn(&C::Three))},
    };
    

    See VS2013 std::function with member function