这是一个简单的问题,但答案非常复杂。简短的答案是你可以做你想用std :: bind1st或boost :: bind做的事情。较长的答案在下面。
编译器无误建议您使用& CLoggersInfra :: RedundencyManagerCallBack。首先,如果RedundencyManagerCallBack是成员函数,则函数本身不属于类CLoggersInfra的任何特定实例。它属于类本身。如果你之前曾经调用过一个静态类函数,你可能会注意到你使用了相同的SomeClass :: SomeMemberFunction语法。由于函数本身是属于类而不是特定实例的“静态”,因此您使用相同的语法。 '&'是必要的,因为从技术上讲,你不直接传递函数 - 函数不是C++中的真实对象。而是在技术上传递函数的内存地址,即指向函数指令在内存中的起始位置的指针。但结果是一样的,你有效地'传递函数'作为参数。
但在这种情况下,这只是问题的一半。正如我所说的,RedundencyManagerCallBack函数不属于任何特定的实例。但是这听起来像是你想把它作为一个回调与一个特定的实例考虑在一起。要理解如何做到这一点,您需要了解成员函数的真正含义:常规未定义的任何类函数带有额外的隐藏参数。
例如:
class A {
public:
A() : data(0) {}
void foo(int addToData) { this->data += addToData; }
int data;
};
...
A an_a_object;
an_a_object.foo(5);
A::foo(&an_a_object, 5); // This is the same as the line above!
std::cout
多少参数时A :: foo的需要?通常情况下,我们会说1.但引导下,foo真的需要2个。考虑A :: foo的定义,它需要一个特定的A实例,以使'this'指针有意义(编译器需要知道'这是)。通常,通过语法MyObject.MyMemberFunction()来指定要“this”的方式。但是这只是用于将MyObject的地址作为MyMemberFunction的第一个参数传递的语法糖。同样,当我们在类定义中声明成员函数时,我们不会将'this'放入参数列表中,但这仅仅是语言设计者为保存输入而提供的礼物。相反,你必须指定一个成员函数是静态的,以便自动退出它以获得额外的'this'参数。如果C++编译器编译上面的例子C代码(原来的C++编译器实际工作这种方式),它可能会写这样的事:
struct A {
int data;
};
void a_init(A* to_init)
{
to_init->data = 0;
}
void a_foo(A* this, int addToData)
{
this->data += addToData;
}
...
A an_a_object;
a_init(0); // Before constructor call was implicit
a_foo(&an_a_object, 5); // Used to be an_a_object.foo(5);
回到你的榜样,现在有一个明显的问题。 'Init'需要一个指向一个参数的函数的指针。但是& CLoggersInfra :: RedundencyManagerCallBack是一个函数的指针,它接受两个参数,它是普通参数和秘密'this'参数。因此,为什么你仍然得到一个编译器错误(作为一个方面说明:如果你曾经使用Python,这种混淆是为什么所有成员函数都需要'self'参数)。
处理这个问题的详细方法是创建一个特殊对象,该对象包含一个指向您想要的实例的指针,并且具有一个名为“run”或“execute”(或重载'()'操作符)的成员函数)它接受成员函数的参数,并简单地使用存储实例上的这些参数调用成员函数。但是这需要你改变'Init'来取你的特殊对象而不是一个原始的函数指针,而且听起来像Init是别人的代码。每次出现这个问题时都要做一个特殊的课程,这会导致代码膨胀。
所以,现在,终于,很好的解决方案,提高::绑定和boost ::功能,每个的文档,你可以在这里找到:
boost::bind docs, boost::function docs
的boost ::绑定将让你需要一个函数和该函数的一个参数,并在该参数被锁定的地方创建一个新函数。所以,如果我有一个函数添加两个整数,我可以使用boost :: bind来创建一个新的函数,其中一个参数被锁定为5,这个新函数只需要一个整数参数,并且总是会添加5个到它。使用这种技术,您可以将隐藏的'this'参数锁定为特定的类实例,并生成一个只需要一个参数的新函数,就像您想要的那样(请注意,隐藏参数始终是第一个参数,正常参数按顺序排列)。看看boost :: bind docs的例子,他们甚至专门讨论了如何将它用于成员函数。从技术上讲,有一个称为std :: bind1st的标准函数,你也可以使用,但boost :: bind更通用。
当然,只有一个捕获。 boost :: bind将会为你提供一个很好的boost :: function,但是这在技术上仍然不像Init可能需要的原始函数指针。值得庆幸的是,boost提供了一种将boost :: function转换为raw指针的方法,如StackOverflow here中所记录。它如何实现这个超出了这个答案的范围,尽管它也很有趣。
不要担心,如果这看起来很可笑 - 你的问题与C++的几个较暗的角相交,而且boost :: bind一旦学习它就会非常有用。
该链接现在是https://isocpp.org/wiki/faq/pointers-to-members#memfnptr-vs-fnptr;看起来他现在说“不要”。这就是为什么只有链接的答案不好。 – 2016-01-12 19:45:11
随意编辑我八岁的答案:-) – 2016-01-12 22:06:25