c++错误的参数类型-函数指针
c++ wrong argument type - function pointer
我有一个函数,它将指向函数的指针作为参数:
void MySolver::set_pt2func(double(*pt2function)(double*))
{
pt2Function = pt2function;
}
在另一个类中,一些方法想要用以下代码初始化实例my_solver:
double (MyClass::*pt2apply)(double* parameter) = NULL;
pt2apply = &MyClass::apply_func;
my_solver->set_pt2func(pt2apply);
最后一行显示编译错误:
error: double (MyClass::*pt2apply)(double*)
argument of type (MyClass::* )(double*) is not compatible
with argument of type double(*)(double*)
如何修复?
谢谢!
编辑
我用这个提示
http://www.parashift.com/c++-faq/memfnptr-to-const-mmfn.html
我设置typedef:
typedef double (MyClass::*Pt2apply_func)(double*) const;
在我的方法中,我尝试了这个:
Pt2apply_func pt2apply = &MyClass::apply_func;
my_solver->set_pt2func(pt2apply);
&MyClass
出现编译错误,具有再次兼容的类型。另一种方式来处理我的问题?谢谢
您需要一个指向函数的指针:
double(*)(double*)
你有一个指向成员函数的指针:
double (MyClass::*)(double*)
这不是一回事。甚至所有类似的东西。第一个可以直接调用;第二个只能通过具有->*
或.*
运算符的对象调用。
这不仅仅是编译器对类型的挑剔;指向成员函数的指针在本质上甚至不是指针(或者至少不是,只是指针);它需要更多的信息来处理动态绑定。
请参阅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); }
现在,这个东西的类型不是double(*)(double*)
。事实上,这是一种未指明的东西,可能是难以形容的丑陋。在这里,我们只是使用了auto
来避免处理它,但我们必须将它传递给set_pt2func
,然后该方法必须将它存储在一个成员变量中,所以我们需要某种可以键入的类型。答案是std::function<double(double *)>
。这是一个对象,可以存储任何可使用double *
调用的内容的副本,并返回double
。因此:
void MySolver::set_pt2func(std::function<double(double*)> pt2function)
{
pt2Function = pt2function;
}
就是这样。
现在,这需要C++11。如果您使用的是C++98,那么您可以使用boost::lambda
而不是C++11 lambdas(更丑陋,但基本思想相同)。或者,您可以使用boost::bind
(与C++11std::bind
几乎相同,后者基于Boost库),或者使用许多其他具有类似功能的库之一。为了存储函子boost::function
(同样,与C++11std::function
几乎相同,尽管有时效率较低)。(如果你有带TR1的C++03,你可能在std
或std::tr1
中有一些C++11功能,但不同的编译器制造商直到C++11几乎完成后才弄清楚所有细节,所以使用它最简单的方法是通过boost::tr1
,如果你有Boost,你还不如直接使用它。)
如果您由于某种原因使用C++98而没有Boost,则可以使用std::mem_fn
,并将结果存储在std::binary_function
中。这要丑得多,所以我不会在这里给出全部细节。
现在让我们来看一下经典的解决方案。只有当你有一个现有的API使用函数指针(例如回调),并且你无法更改它时,这才是真正值得做的。我建议寻找使用qsort_r
等C函数的示例代码,因为想法基本相同:你将函数指针与"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);
请注意,如果您使用指向成员函数的pt2apply
指针,那么您应该在包装器中使用->*
来调用它。但我们不再需要pt2apply
;包装器可以只调用具有CCD_ 32的CCD_。
然后,当MySSolver想要调用函数时,它会执行以下操作:
pt2Function(parameter, userInfo);
最后一件事是:wrapMyClassPt2Apply不能是成员函数,否则您将陷入与刚开始时相同的问题;指向它的指针将是指向成员函数的指针,而不是指针。所以,你有两个选择:
使其成为一个免费函数。这是一个非常合理的做法。自由函数可以是类接口的一部分。或者,它们可以比私有方法隐藏得更好(将它们放在.cpp文件中,而在.h文件中根本不提及它们)。
使其成为静态方法。有些人更喜欢这样,但实际上,只有当MyClass.cpp之外的人要进行
set_pt2func
调用,并且已经是MyClass
的朋友(或子类)时,这才是有益的,因为这样你就可以将该方法设为私有(或受保护)。
没有简单的解决方案。指向成员函数的指针是不同的,因为它们需要调用一个对象。MySolver
将如何提供MyClass
?基本上,一旦你有了答案,基本问题就基本上消失了。两种常见的解决方案是MySolver
知道MyClass
,在这种情况下,您可以修复set_pt2func的签名,或者向MySolver
提供std::bind(pt2apply, SomeObj, _1)
的结果。
指向成员函数的指针与常规指针(c样式函数指针)不兼容。这是因为成员采用了一个不属于签名的隐式this
参数。如果您想实现类似的行为,请查看boost::bind。
使用C++11而不是C。这意味着:使用std::function
和std:mem_fn
绑定成员函数。
- QMetaObject invokeMethod的基于函数指针的语法
- C++-试图将函数指针推回到另一个CPP文件中的矢量时出错
- c++r值引用应用于函数指针
- 模板函数指针和lambda
- 是否可以将llvm::FunctionType转换为C/C++原始函数指针
- 带有类的函数指针
- () 函子后面的括号,而不是函数指针?
- 全局作用域中函数指针的赋值
- 使用"Task"函数指针队列定义作业管理器
- 将成员函数指针作为参数传递给模板方法
- 如何创建对象函数指针C++映射?
- 匹配函数指针作为模板参数?
- 通过函数指针定义类范围之外的方法
- 存储在类中的函数指针
- C++从函数指针数组调用函数
- 将返回值存储在函数指针数组的指针中是如何工作的?
- 整数键映射到头文件中的成员函数指针
- 从类成员函数到类 C 函数指针的转换
- 如何将内联匿名函数分配给C++函数指针
- 将字符缓冲区强制转换为函数指针