【问题标题】:Tables of C++ member functionsC++ 成员函数表
【发布时间】:2012-01-26 17:16:57
【问题描述】:

我需要一个将代码映射到 C++ 成员函数的表。假设我们有这个类:

class foo
{
  bool one() const;
  bool two() const;
  bool call(char*) const;
};

我想要的是这样的表格:

{
  { “somestring”,  one },
  { ”otherstring”, two }
};

如果我有一个foo 对象ff.call(”somestring”) 会在表中查找“somestring”,调用one() 成员函数,并返回结果。

所有被调用的函数都有相同的原型,即它们是 const,不带参数,返回 bool。

这可能吗?怎么样?

【问题讨论】:

  • 这一切都可以手工完成。一个更有趣的问题是自动执行的最佳方法是什么。

标签: c++ arrays data-structures member-function-pointers


【解决方案1】:

是的,这是可能的,使用 pointer to member 语法。

使用您提供的原型,地图将是。

std::map< std::string, bool( foo::*)() const>

会用这种语法调用

this->*my_map["somestring"]();

那个看起来很奇怪的-&gt;* 运算符用于指向成员函数的指针,由于继承,它可能有一些奇怪的考虑。 (这不仅仅是一个原始地址,正如-&gt; 所期望的那样)

【讨论】:

  • @MooingDuck:谢谢。我忽略了const
【解决方案2】:

由于你只需要存储同一个类的成员,具有相同的参数和返回类型,你可以使用指向成员函数的指针:

bool foo::call(char const * name) const {
    static std::map<std::string, bool (foo::*)() const> table 
    {
        {"one", &foo::one}, 
        {"two", &foo::two}
    };

    auto entry = table.find(name);
    if (entry != table.end()) {
        return (this->*(entry->second))();
    } else {
        return false;
    }
}

这使用了 C++11 的新初始化语法。如果您的编译器不支持它,还有其他各种选择。您可以使用静态函数初始化地图:

typedef std::map<std::string, bool (foo::*)() const> table_type;
static table_type table = make_table();

static table_type make_table() {
    table_type table;
    table["one"] = &foo::one;
    table["two"] = &foo::two;
    return table;
}

或者你可以使用Boost.Assignment:

static std::map<std::string, bool (foo::*)() const> table = 
    boost::assign::map_list_of
        ("one", &foo::one)
        ("two", &foo::two);

或者你可以使用一个数组,并使用std::find_if(或者一个简单的for循环,如果你的库还没有),或者std::binary_search,如果你确保数组是排序的。

【讨论】:

  • +1 用于使用auto。不然写std::map&lt;std::string, bool (foo::*)() const&gt;::iterator太丑了!
  • 我喜欢这种方法的优雅和简单,但我不认为可以像这样初始化map?无论如何,MSVC 不喜欢它。
  • @chrisd:这是新的 C++11 初始化语法。如果您的编译器不支持,我添加了一些替代方案。
  • 知道了,谢谢。我已经通过从类似于下面 Nawaz 显示的表中初始化地图来实现这一点,但我试图理解您的原始语法。我想是时候研究 C++11 了。再次感谢。
【解决方案3】:

是的。

struct foo_method
{
   std::string name;
   bool (foo::*pfun)() const;
};

foo_method methodTable[] = 
{
  { “somestring”,  &foo::one },
  { ”otherstring”, &foo::one }
};

void foo::call(const char* name) const
{
   size_t size = sizeof(methodTable)/sizeof(*methodTable);
   for(size_t i = 0 ; i < size ; ++i)
   {
       if ( methodTable[i].name == name )
       {
           bool (foo::*pfun)() const = methodTable[i].pfun;
           (this->*pfun)(); //invoke
       }
   }
}

【讨论】:

  • 我想我更喜欢地图而不是表格,但这个想法是有效的。
【解决方案4】:

我会选择boost::functionstd::map。具体来说,是这样的:

typedef boost::function<bool()> MyFunc;
typedef std::map<std::string, MyFunc> MyFuncMap;

然后,给定一个 MyFuncMap 的实例,您可以执行 map["something"]()。然后你可以将它包装在一个重载operator() 的类中。您可以使用函数指针/引用,但我更喜欢使用boost::function,因为它允许我将指针绑定到成员函数(使用 boost::bind)或使用其他函数对象。您还可以像使用常规函数指针一样在条件中测试boost::function

这里是相关文档:

祝你好运!

编辑:关于你关于 const 成员和boost::function 的问题,这里有一个例子:

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

typedef boost::function<bool ()> FuncPtr;

struct Test
{
    bool test() const
    {
        std::cout << "yay" << std::endl;
    }
};

int main(int argc, char **argv)
{
    Test t;
    FuncPtr ptr = boost::bind(&Test::test, &t);
    ptr();
}

【讨论】:

  • const 是函数类型的一部分,但我不知道它如何与boost::function 交互。它应该是声明的一部分吗?
  • 刚刚查看了一下,似乎boost::function&lt;bool ()&gt; 对 const 和非 const 成员都适用。不太清楚如何或为什么,但它有效。
【解决方案5】:

我想补充一点,如果没有一个类的实例可以调用它,那么指向成员函数的指针是没有意义的。您所描述的情况说明了这一点(我想您知道这一点),但是在其他情况下,可能需要用指针或引用封装函数指针,以某种@987654321 对应的实例@构造。

【讨论】:

    猜你喜欢
    • 2018-10-09
    • 2014-07-29
    • 1970-01-01
    • 2015-12-14
    • 1970-01-01
    • 2012-02-29
    • 2013-02-15
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多