使用带有继承的成员函数指针的unordered_map,使用std:function

时间:2016-03-10 17:52:48

标签: c++ inheritance stl function-pointers

我正在尝试创建和使用成员函数指针的unordered_map,作为接口的一部分,由子类继承和使用。最终目标是允许脚本使用子类(“可编写脚本”),以便可以通过文本“命令”调用它们的函数。

我遇到了语法问题,以及涉及成员函数指针及其继承和使用的困难。我尝试了很多变化,但这是一个复杂而微妙的问题,正如我的谷歌搜索给我看到的那样。

界面:

#include <string>
#include <vector>
#include <unordered_map>
#include <functional>

using namespace std;

class IScriptable
{
    public:
        virtual void Init() = 0;
        bool Run_Script_Command(string i_Command, vector<string> i_Arguments);
    protected:
        void Register_Command_Function_Pair(string i_Command, function<void(const IScriptable&, vector<string>)> i_Function);

        unordered_map<string, function<void (const IScriptable&, vector<string>)>> m_Command_Functions;
};

bool IScriptable::Run_Script_Command(string i_Command, vector<string> i_Arguments)
{
    if (m_Command_Functions.find(i_Command) != m_Command_Functions.end())
    {
        (m_Command_Functions[i_Command])(*this, i_Arguments);
    }
    else
    {
        return(false);
    }

    return(true);
}

void IScriptable::Register_Command_Function_Pair(string i_Command, function<void(const IScriptable&, vector<string>)> i_Function)
{
    m_Command_Functions[i_Command] = i_Function;
}

子对象:

class Child : public IScriptable
{
    public:
        virtual void Init();
    protected:
        void Foo(vector<string> parms); // The function I'm going to try and add and invoke later
};

void Child::Init()
{
    Register_Command_Function_Pair("TestFunction", &Child::Foo);
}

void Child::Foo(vector<string> parms)
{
    cout << "Calling Foo\n";
    for (vector<string>::iterator it = parms.begin(); it != parms.end(); it++)
    {
        cout << *it;
        cout << "\n";
    }
}

代码使用示例:

int main()
{
    Child c;
    c.Init();

    vector<string> arguments;
    arguments.push_back("Testing");
    arguments.push_back("123");
    c.Run_Script_Command("TestFunction", arguments);

    // Expected output:
    // Calling Foo
    // Testing
    // 123  
}

我试图创建一个我正在尝试做的简化示例,所以希望我的目标有意义,即使有一些其他糟糕的设计决策(为了示例而制作)。

如何编译并给出预期的输出?

感谢。

编辑:上面的代码应抛出以下编译器错误:

C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\include\functional(506): error C2664: 'void std::_Func_class<_Ret,const IScriptable &,std::vector<std::string,std::allocator<_Ty>>>::_Set(std::_Func_base<_Ret,const IScriptable &,std::vector<_Ty,std::allocator<_Ty>>> *)' : cannot convert argument 1 from '_Myimpl *' to 'std::_Func_base<_Ret,const IScriptable &,std::vector<std::string,std::allocator<_Ty>>> *'
          with
          [
              _Ret=void
  ,            _Ty=std::string
          ]
          Types pointed to are unrelated; conversion requires reinterpret_cast, C-style cast or function-style cast
          C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\include\functional(442) : see reference to function template instantiation 'void std::_Func_class<_Ret,const IScriptable &,std::vector<std::string,std::allocator<_Ty>>>::_Do_alloc<_Myimpl,_Fret(__cdecl Child::* const &)(std::vector<_Ty,std::allocator<_Ty>>),_Alloc>(_Fty,_Alloc)' being compiled
          with
          [
              _Ret=void
  ,            _Ty=std::string
  ,            _Fret=void
  ,            _Alloc=std::allocator<std::_Func_class<void,const IScriptable &,std::vector<std::string,std::allocator<std::string>>>>
  ,            _Fty=void (__cdecl Child::* const &)(std::vector<std::string,std::allocator<std::string>>)
          ]
          C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\include\functional(442) : see reference to function template instantiation 'void std::_Func_class<_Ret,const IScriptable &,std::vector<std::string,std::allocator<_Ty>>>::_Do_alloc<_Myimpl,_Fret(__cdecl Child::* const &)(std::vector<_Ty,std::allocator<_Ty>>),_Alloc>(_Fty,_Alloc)' being compiled
          with
          [
              _Ret=void
  ,            _Ty=std::string
  ,            _Fret=void
  ,            _Alloc=std::allocator<std::_Func_class<void,const IScriptable &,std::vector<std::string,std::allocator<std::string>>>>
  ,            _Fty=void (__cdecl Child::* const &)(std::vector<std::string,std::allocator<std::string>>)
          ]
          C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\include\functional(442) : see reference to function template instantiation 'void std::_Func_class<_Ret,const IScriptable &,std::vector<std::string,std::allocator<_Ty>>>::_Reset_alloc<_Fret,Child,std::vector<_Ty,std::allocator<_Ty>>,std::allocator<std::_Func_class<_Ret,const IScriptable &,std::vector<_Ty,std::allocator<_Ty>>>>>(_Fret (__cdecl Child::* const )(std::vector<_Ty,std::allocator<_Ty>>),_Alloc)' being compiled
          with
          [
              _Ret=void
  ,            _Ty=std::string
  ,            _Fret=void
  ,            _Alloc=std::allocator<std::_Func_class<void,const IScriptable &,std::vector<std::string,std::allocator<std::string>>>>
          ]
          C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\include\functional(442) : see reference to function template instantiation 'void std::_Func_class<_Ret,const IScriptable &,std::vector<std::string,std::allocator<_Ty>>>::_Reset_alloc<_Fret,Child,std::vector<_Ty,std::allocator<_Ty>>,std::allocator<std::_Func_class<_Ret,const IScriptable &,std::vector<_Ty,std::allocator<_Ty>>>>>(_Fret (__cdecl Child::* const )(std::vector<_Ty,std::allocator<_Ty>>),_Alloc)' being compiled
          with
          [
              _Ret=void
  ,            _Ty=std::string
  ,            _Fret=void
  ,            _Alloc=std::allocator<std::_Func_class<void,const IScriptable &,std::vector<std::string,std::allocator<std::string>>>>
          ]
          C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\include\functional(671) : see reference to function template instantiation 'void std::_Func_class<_Ret,const IScriptable &,std::vector<std::string,std::allocator<_Ty>>>::_Reset<void,Child,std::vector<_Ty,std::allocator<_Ty>>>(_Fret (__cdecl Child::* const )(std::vector<_Ty,std::allocator<_Ty>>))' being compiled
          with
          [
              _Ret=void
  ,            _Ty=std::string
  ,            _Fret=void
          ]
          C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\include\functional(671) : see reference to function template instantiation 'void std::_Func_class<_Ret,const IScriptable &,std::vector<std::string,std::allocator<_Ty>>>::_Reset<void,Child,std::vector<_Ty,std::allocator<_Ty>>>(_Fret (__cdecl Child::* const )(std::vector<_Ty,std::allocator<_Ty>>))' being compiled
          with
          [
              _Ret=void
  ,            _Ty=std::string
  ,            _Fret=void
          ]
          Source\GoDatabase.cpp(3436) : see reference to function template instantiation 'std::function<void (const IScriptable &,std::vector<std::string,std::allocator<_Ty>>)>::function<void(__cdecl Child::* )(std::vector<_Ty,std::allocator<_Ty>>)>(_Fx &&)' being compiled
          with
          [
              _Ty=std::string
  ,            _Fx=void (__cdecl Child::* )(std::vector<std::string,std::allocator<std::string>>)
          ]
          Source\GoDatabase.cpp(3436) : see reference to function template instantiation 'std::function<void (const IScriptable &,std::vector<std::string,std::allocator<_Ty>>)>::function<void(__cdecl Child::* )(std::vector<_Ty,std::allocator<_Ty>>)>(_Fx &&)' being compiled
          with
          [
              _Ty=std::string
  ,            _Fx=void (__cdecl Child::* )(std::vector<std::string,std::allocator<std::string>>)
          ]

1 个答案:

答案 0 :(得分:0)

您的功能类型应为:

std::function<void(std::vector<std::string>)>

const IScriptable&在那里不起作用,如果你想使用指针方法,那将是完全不同的语法。

然后Init()就是这样:

using namespace std::placeholders;
Register_Command_Function_Pair("TestFunction", std::bind( &Child::Foo, this, _1 ) );

Run_Script_Command()变为:

bool IScriptable::Run_Script_Command(string i_Command, vector<string> i_Arguments)
{
    auto f = m_Command_Functions.find(i_Command);
    if ( f != m_Command_Functions.end())
    {
        f->second(i_Arguments);
        return true;
    }
    return false;
}

请注意,您应该为正在使用的typedef创建类型别名(usingstd::function),因为您多次使用它。这将使代码更具可读性,并且更容易更改该类型。