kir*_*off 1 c++ types pointers compiler-errors function-pointers
我有一个函数,它将一个指向函数的参数作为参数:
void MySolver::set_pt2func(double(*pt2function)(double*))
{
pt2Function = pt2function;
}
Run Code Online (Sandbox Code Playgroud)
在另一个类中,某些方法想要使用以下代码初始化实例my_solver:
double (MyClass::*pt2apply)(double* parameter) = NULL;
pt2apply = &MyClass::apply_func;
my_solver->set_pt2func(pt2apply);
Run Code Online (Sandbox Code Playgroud)
最后一行显示编译错误:
error: double (MyClass::*pt2apply)(double*)
argument of type (MyClass::* )(double*) is not compatible
with argument of type double(*)(double*)
Run Code Online (Sandbox Code Playgroud)
怎么修?
谢谢!
编辑
我用这个小费
http://www.parashift.com/c++-faq/memfnptr-to-const-memfn.html
我设置了typedef:
typedef double (MyClass::*Pt2apply_func)(double*) const;
Run Code Online (Sandbox Code Playgroud)
在我的方法中,我试试这个:
Pt2apply_func pt2apply = &MyClass::apply_func;
my_solver->set_pt2func(pt2apply);
Run Code Online (Sandbox Code Playgroud)
和编译错误显示&MyClass,再次兼容类型.处理我的问题的其他方法?谢谢!
你需要一个指向函数的指针:
double(*)(double*)
Run Code Online (Sandbox Code Playgroud)
你有一个指向成员的函数:
double (MyClass::*)(double*)
Run Code Online (Sandbox Code Playgroud)
这些都不是一回事.甚至是所有类似的.第一个可以直接调用; 第二个只能通过一个对象调用,使用->*或.*运算符.
这不仅仅是编译器对类型的挑剔; 一个指针到成员函数甚至不是一个指针(或至少不只是一个指针)在幕后; 它需要更多信息才能处理动态绑定.
有关详细信息,请参阅http://www.parashift.com/c++-faq/pointers-to-members.html.
使用带有C风格API的指针到成员函数的"经典"方法是编写一个包装函数,该函数MyClass*从其他地方获取(通常是"userinfo","thunk"等,随函数指针一起传递)并myobj->*pmf(args)用它来打电话.然后,您可以将指针传递给该包装器,因为它只是一个普通的函数.更聪明的现代方式包括bind和lambdas.
让我们首先处理现代方式,因为它更简单,如果可以的话,这就是你应该做的.首先,如果你有C++ 11,你可以使用std::bind,或者std::mem_fn,或者只写一个lambda:
auto pt2apply = [&](double *parameter) { return my_solver->pt2apply(parameter); }
Run Code Online (Sandbox Code Playgroud)
现在,这件事的类型不是double(*)(double*).事实上,这是一个未指明的东西,可能是难以言喻的难看.这里我们习惯于auto避免处理它,但是我们必须将它传递给set_pt2func,然后该方法必须将它存储在成员变量中,因此我们需要某种类型的类型.答案是std::function<double(double *)>.这是一个对象,可以存储任何可用a调用的东西的副本double *并返回a double.所以:
void MySolver::set_pt2func(std::function<double(double*)> pt2function)
{
pt2Function = pt2function;
}
Run Code Online (Sandbox Code Playgroud)
就是这样.
现在,这需要C++ 11.如果你正在使用C++ 98,你可以使用boost::lambda而不是C++ 11 lambdas(很多丑陋,但基本的想法相同).或者您可以使用boost::bind(几乎与std::bind基于Boost库的C++ 11相同),或者具有类似功能的许多其他库之一.并存储仿函数boost::function(再次,几乎与C++ 11相同std::function,但有时效率较低).(如果你有TR1的C++ 03,你可能有一些C++ 11的功能,std或者std::tr1不同的编译器制造商并没有在C++ 11差不多完成之前完全理解细节,所以最简单的方法就是通过boost::tr1,如果你有Boost,你也可以使用它.)
如果由于某种原因你坚持使用C++ 98而没有Boost,你可以使用std::mem_fn,并将结果存储在一个std::binary_function.这是非常丑陋的,所以我不会在这里详细说明.
现在让我们来看看经典的解决方案.当你有一个使用函数指针的现有API(例如回调)时,这真的值得做,你无法改变它.我建议寻找使用C函数的示例代码qsort_r,因为这个想法几乎相同:你将一个函数指针与一个"thunk"一起传递,并且它们中的两个总是一起旅行.(现代解决方案基本上都是将两个东西绑定到一个对象中,您可以调用它而无需跟踪thunk,使代码更易于读写,并且编译器更容易捕获错误. )
这里的关键是你需要一个包装函数,一个普通的C风格的函数,你可以使用函数指针.你的thunk将成为你MyClass对象的指针.在我的例子中,我将通过thunk作为一个void *因为,即使这显然是低劣的(更多的代码编写,编译器捕获错误的机会更少),这是你最常见到的您需要处理的通用C API.
所以,把它们放在一起:
void MySolver::set_pt2func(double(*pt2function)(double*, void *), void *userinfo)
{
pt2Function = pt2function;
userInfo = userinfo;
}
double wrapMyClassPt2Apply(double *parameter, void *userinfo)
{
return ((MyClass*)userinfo)->apply_func(parameter);
}
my_solver->set_pt2func(wrapMyClassPt2Apply, (void *)my_solver);
Run Code Online (Sandbox Code Playgroud)
请注意,如果您使用pt2apply指向成员函数的指针,则可以->*在包装器中调用它.但我们不再需要pt2apply了; 包装器可以只调用apply_func成员->.
然后,当MySolver想要调用该函数时,它会这样做:
pt2Function(parameter, userInfo);
Run Code Online (Sandbox Code Playgroud)
最后一件事:wrapMyClassPt2Apply不能是一个成员函数,或者你遇到了与你开始时相同的问题; 指向它的指针将是指向成员函数的指针而不是指针.所以,你有两个选择:
使它成为一个免费的功能.这是一件非常合理的事情.自由函数可以是类的接口的一部分.或者,它们可以隐藏得比私有方法更好(通过将它们放在.cpp文件中而不在.h文件中完全提及它们).
使它成为一种静态方法.有些人更喜欢这个,但实际上,唯一有利的是当MyClass.cpp之外的某个人要进行set_pt2func调用,并且已经是朋友(或子类)时MyClass,因为那时你可以将该方法设为私有(或者保护).