【问题标题】:How to create map<string, class::method> in c++ and be able to search for function and call it?如何在 C++ 中创建 map<string, class::method> 并能够搜索函数并调用它?
【发布时间】:2011-03-07 23:43:37
【问题描述】:

我正在尝试在 C++ 中创建字符串和方法的映射,但我不知道该怎么做。我想做这样的事情(伪代码):

map<string, method> mapping =
{
  "sin", Math::sinFunc,
  "cos", Math::cosFunc,
  ...
};

...

string &function;
handler = mapping.find(function);
int result;

if (handler != NULL)
  result = (int) handler(20);

老实说,我不知道在 C++ 中是否可行。我想要一个字符串、方法的映射,并且能够在我的映射中搜索函数。如果存在给定的函数字符串名称,那么我想用给定的参数调用它。

【问题讨论】:

    标签: c++ mapping function-pointers


    【解决方案1】:

    好吧,我不是这里流行的 Boost Lovers Club 的成员,所以就这样吧 - 使用原始 C++。

    #include <map>
    #include <string>
    
    struct Math
    {
        double sinFunc(double x) { return 0.33; };
        double cosFunc(double x) { return 0.66; };
    };
    
    typedef double (Math::*math_method_t)(double);
    typedef std::map<std::string, math_method_t> math_func_map_t;
    
    int main()
    {
    
        math_func_map_t mapping;
        mapping["sin"] = &Math::sinFunc;
        mapping["cos"] = &Math::cosFunc;
    
        std::string function = std::string("sin");
        math_func_map_t::iterator x = mapping.find(function);
        int result = 0;
    
        if (x != mapping.end()) {
            Math m;
            result = (m.*(x->second))(20);
        }
    }
    

    如果我正确理解你想要一个方法指针,而不是函数/静态方法指针,那显然是这样。

    【讨论】:

    • 顺便说一句,该方法也适用于虚函数。这也是在 C++ 中不能将指针转换为 long 的情况:对于指向虚拟方法的指针,编译器会在指针中添加一些额外的东西以允许多态性。
    • 是否可以使用任何类的方法来做到这一点?某种不关心它是谁的方法的通用指针?
    【解决方案2】:
    //pick one
    typedef float (*func_type_1)(float);
    typedef boost::function<float(float)> func_type_2;
    
    std::map<std::string,func_type> fm;
    fm["sin"] = &Math::sin;
    fm["cos"] = &Math::cos;
    
    auto f = fm[str];
    result = f(42);
    

    【讨论】:

      【解决方案3】:

      这在 C++ 中确实是可能的,这要归功于函数指针。这是一个简单的例子:

        std::string foo() { return "Foo"; }
        std::string bar() { return "Bar"; }
      
        int main()
        {
            std::map<std::string, std::string (*)()> m;
      
            // Map the functions to the names
            m["foo"] = &foo;
            m["bar"] = &bar;
      
            // Display all of the mapped functions
            std::map<std::string, std::string (*)()>::const_iterator it = m.begin();
            std::map<std::string, std::string (*)()>::const_iterator end = m.end();
      
            while ( it != end ) {
                std::cout<< it->first <<"\t\""
                    << (it->second)() <<"\"\n";
                ++it;
            }
        }
      

      在处理具有不同返回类型和参数的函数时,这会变得更加棘手。另外,如果你包含非静态成员函数,你应该使用Boost.Function

      【讨论】:

        【解决方案4】:

        我认为这可行,假设您的函数返回 int 并采用单个 int 参数:

        map<string, int(*func)(int)>
        

        如果函数参数类型或返回值不同,我认为你不能这样做。

        【讨论】:

          【解决方案5】:

          最简单的方法是使用boost::function:

          #include <map>
          #include <string>
          #include <boost/function.hpp>
          
          using namespace std;
          
          // later...
          
          map<string, boost::function<double(double)> > funcs;
          funcs["sin"] = &Math::sinFunc;
          

          如果您使用成员函数,它会稍微复杂一些 - boost::lambda 可以提供帮助:

          #include <map>
          #include <string>
          #include <boost/function.hpp>
          #include <boost/lambda/bind.hpp>
          
          using namespace std;
          namespace l = boost::lambda;
          
          // later...
          
          Math *m = new Math();
          map<string, boost::function<double(double)> > funcs;
          funcs["sin"] = l::bind(&Math::sinFunc, m, l::_1);
          

          【讨论】:

          • 为什么要使用boost::lambda::bind 而不仅仅是boost::bind
          • 我只是求助于 boost::lambda 来满足我所有的函数绑定需求。这比学习两个功能重叠的独立库要容易:)
          【解决方案6】:

          this questionmethod 最方便的表示法是 function&lt;signature&gt;,其中 function 包含在 boost 或 C++0x 下的 &lt;utility&gt; 中。

          在你的情况下,签名是这样的。

          map<string, function<double (double)> map; ...
          
          map["sin"](1.0); 
          

          【讨论】:

            【解决方案7】:

            您当然可以哄骗 map 容器将字符串映射到函数指针。但这对于做一些相当简单的事情来说是一种非常困难的方法。

            创建所有函数名称的枚举。将字符串名称映射到枚举值。然后使用 switch 语句根据枚举值调用函数。你可以避免头发变白。

            【讨论】:

              猜你喜欢
              • 2019-03-29
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多