C++ 通过C&x2B+;方法作为函数指针
我有一个类方法:C++ 通过C&x2B+;方法作为函数指针,c++,C++,我有一个类方法: bool sendRequest(DataFieldList& requestParams, DataFieldList& responseParams, std::string context, void(*sendFailure)() = NULL); SeDebug是一个可选的函数指针,在我的C++类中,我有一个例子: sendRequest(param
bool sendRequest(DataFieldList& requestParams,
DataFieldList& responseParams,
std::string context, void(*sendFailure)() = NULL);
SeDebug是一个可选的函数指针,在我的C++类中,我有一个例子:
sendRequest(paramList, responseList, "Could not set background lighting control brightness limit", HBCMaxBrightnessLimitSendFailure);
HBCMaxBrightnessLimitSendFailure在类中声明为私有方法:
void HBCMaxBrightnessLimitSendFailure();
当我构建此应用程序时,会出现以下错误:
lightingsystemcomponent.cpp(969): error C3867: 'Lighting::SystemComponent_impl::HBCMaxBrightnessLimitSendFailure': function call missing argument list; use '&Lighting::SystemComponent_impl::HBCMaxBrightnessLimitSendFailure' to create a pointer to member
我还尝试:
sendRequest(paramList, responseList, "Could not set background lighting control brightness limit", HBCMaxBrightnessLimitSendFailure());
这将错误更改为:
lightingsystemcomponent.cpp(969): error C2664: 'bool Lighting::SystemComponent_impl::sendRequest(DataFieldList &, DataFieldList &,std::string,void (__cdecl *)(void))' : cannot convert argument 4 from 'void' to 'void (__cdecl *)(void)'
void类型的表达式无法转换为其他类型
我已经做了一些改变,并尝试实施斯宾塞提出的建议,新原型:
bool sendRequest(DataFieldList& requestParams,
DataFieldList& responseParams,
std::string context,
std::function<void()> sendFailure = NULL);
下面是调用此例程和我传递的回调函数的类的示例:
void component::onFailure() {
...Do something...
}
void component::update() {
... Some set-up to build paramlist ...
LightingEngine* engine = getLightingEngine();
assert(engine != nullptr);
engine->sendRequest(¶mList, &responseList, "Some context text", [this]()->void { onFailure(); });
}
编辑:
如果您可以更改SeNeDebug的签名,并且使用的是相当现代的C++(11或更高),那么我会选择<代码> STD::函数< /C> > /P>
#include <functional>
bool sendRequest(DataFieldList& requestParams,
DataFieldList& responseParams,
std::string context, std::function<void()> sendFailure = nullptr);
bool sendRequest(DataFieldList& requestParams,
DataFieldList& responseParams,
std::string context,
const std::function<void()> &sendFailure = nullptr);
或不带lambda但带bind:
sendRequest(paramList, responseList, "Could not set background lighting control brightness limit", std::bind(&Lighting::SystemComponent_impl::HBCMaxBrightnessLimitSendFailure,this));
旧帖子:
试试编译器告诉你的
&Lighting::SystemComponent_impl::HBCMaxBrightnessLimitSendFailure
因此:
成员函数不能直接转换为函数指针,因为它具有调用它的对象的隐式参数(您将其视为成员中的
this
指针)。解决这个问题并不像我想象的那么容易
最佳解决方案是什么,取决于您的用例。如果调用者和被调用者都是成员函数,并且确实依赖于从中调用它们的对象(这两者都是相同的),则添加另一个成员函数指针作为参数。如果传递的成员函数不依赖于其对象,则将其设为静态,这样就没有问题了。对于介于两者之间的所有内容,它都会变得棘手。非静态类成员函数不同于非类函数,因为它需要类的实例才能工作。在你的声明中
bool sendRequest(DataFieldList& requestParams,
DataFieldList& responseParams,
std::string context, void(*sendFailure)() = NULL);
sendFailure
被声明为非成员函数。如果必须这样做,您将永远无法绑定到非静态成员函数
最简单的方法是将HBCMaxBrightnessLimitSendFailure
声明为static
,甚至将其全部移出类,但这仅在不依赖于类的状态时才起作用
假设您有许多不同的失败函数,它们在不同的时间传递。如果只有一个,不要传入函数指针。而是通过一个bool:
bool sendRequest(DataFieldList& requestParams,
DataFieldList& responseParams,
bool sendFailure = false)
{
// ...
if (sendFailure) HBCMaxBrightnessLimitSendFailure();
// ...
}
可以使用指向成员函数的指针,但需要类的实例。如果sendRequest
和HBCMaxBrightnessLimitSendFailure
属于同一类别,请使用此
bool sendRequest(DataFieldList& requestParams,
DataFieldList& responseParams,
std::string context,
void(lightingsystemcomponent::*sendFailure)()= 0);
{
if (sendFailure !=0) this ->*sendFailure();
}
...
sendRequest (request, response, ctxt, &HBCMaxBrightnessLimitSendFailure);
最灵活的方法(以少量开销为代价)是将sendFailure
参数重新声明为std::function
:
bool sendRequest(DataFieldList& requestParams,
DataFieldList& responseParams,
std::string context, std::function<void()> sendFailure);
如果函数参数需要是一个裸函数,例如为了传递给一个C API调用,事情就会变得一团糟。带有捕获的lambda永远不会起作用。这种“有状态”lambda是一个动态创建的类,函数指针和捕获值作为数据成员。并且不能将C++类传递到C函数中。
但是您需要一个类的实例来使用member函数!啊!它唯一需要的是从函数中访问类的全局实例:
void LightingEngine::sendRequest(DataFieldList& requestParams,
DataFieldList& responseParams,
std::string context,
std::function<void()> sendFailure) {
if ( sendFailure != NULL ) {
sendFailure();
}
class lightingsystemcomponent
{
static lightingsystemcomponent*api_context;
static void HBCMaxBrightnessLimitSendFailure()
{
api_context-> something();
}
bool sendRequest(DataFieldList& requestParams,
DataFieldList& responseParams,
std::string context, void(*sendFailure)() = NULL);
};
// ...
api_context = this;
sendRequest(request, response, "context", HBCMaxBrightnessLimitSendFailure());
这类似于有状态lambda为您所做的事情,但您可以将其传递到C库,但需要付出一定的代价。您可以将
sendFailure
声明为成员函数指针
bool sendRequest(DataFieldList& requestParams,
DataFieldList& responseParams,
std::string context,
void(Lighting::SystemComponent_impl::*sendFailure)() = nullptr);
这将允许你写一行很长的字:
sendRequest(paramList, responseList, "Could not set background lighting control brightness limit", &Lighting::SystemComponent_impl::HBCMaxBrightnessLimitSendFailure);
另一个选项是使用
std::function
#include <functional>
bool sendRequest(DataFieldList& requestParams,
DataFieldList& responseParams,
std::string context, std::function<void()> sendFailure = nullptr);
bool sendRequest(DataFieldList& requestParams,
DataFieldList& responseParams,
std::string context,
const std::function<void()> &sendFailure = nullptr);
执行回调的惯用“C++方法”是使用函数模板。这类似于使用
std::function
,但性能要高得多
template <typename Func>
bool sendRequest(DataFieldList& requestParams,
DataFieldList& responseParams,
std::string context,
Func sendFailure);
然后像这样调用sendRequest
:
sendRequest(paramList, responseList, "Could not set background lighting control brightness limit", [this]{ HBCMaxBrightnessLimitSendFailure() });
sendRequest(paramList, responseList, "Could not set background lighting control brightness limit", [this]{ HBCMaxBrightnessLimitSendFailure() });
如果您将
void(*sendFailure)(
函数指针更改为std::function
,那么我认为您可以执行您想要的操作:
void printFunc(int a, std::function<void(void)> f)
{
std::cout << a << '\t';
if (f)
f();
else
std::cout << "f is null" << std::endl;
}
void testFunc()
{
std::cout << "testFunc" << std::endl;
}
class A
{
private:
void privatePrint() { std::cout << "privatePrint " << a << std::endl; }
int a;
public:
A(int i) : a { i } {}
void print()
{
printFunc(a, [this]() {this->privatePrint();} );
}
};
class B
{
private:
static void staticPrint() { std::cout << "staticPrint" << std::endl; }
int b;
public:
B(int i) : b{ i } {}
void print()
{
printFunc(b, staticPrint);
}
};
struct C
{
void operator()() { std::cout << "operator()" << std::endl; }
};
int main()
{
printFunc(1, testFunc);
A a{ 2 };
a.print();
B b{ 3 };
b.print();
printFunc(4, nullptr);
C c;
printFunc(5, c);
}
这只在方法是静态的情况下有效(它似乎不是来自OPs问题)。啊,sry,你当然是对的@Kerndog73。我会相应地更新它。那怎么办呢?可以取函数指针
std::mem_fn
,但它有另一个参数指向调用对象(我们将隐式参数显式化)。如果您将一个对象绑定到该对象,它将是有状态的,并且您再次无法获取函数指针。这是否回答了您的问题?请不要这样故意破坏你的问题,尤其是当人们费心回答的时候。我已经为您回滚了您的编辑。@TobySpeight,很公平,是无知和贬损性的评论导致我想要关闭或删除它,但我看到这些评论现在已经被删除,谢谢。我想问题是您使用的是NULL
而不是nullptr
@Kerndog73,非常好,很好,谢谢@这和我的答案很相似。你认为什么不对?我投了赞成票。@Splaten我添加了一些可能性。谢谢你的时间和努力,我编辑了我的原始帖子,以显示我试图实施你的建议,你能看出有什么问题吗?
bool sendRequest(DataFieldList& requestParams,
DataFieldList& responseParams,
std::string context);
sendRequest(paramList, responseList, "Could not set background lighting control brightness limit", [this]{ HBCMaxBrightnessLimitSendFailure() });
void printFunc(int a, std::function<void(void)> f)
{
std::cout << a << '\t';
if (f)
f();
else
std::cout << "f is null" << std::endl;
}
void testFunc()
{
std::cout << "testFunc" << std::endl;
}
class A
{
private:
void privatePrint() { std::cout << "privatePrint " << a << std::endl; }
int a;
public:
A(int i) : a { i } {}
void print()
{
printFunc(a, [this]() {this->privatePrint();} );
}
};
class B
{
private:
static void staticPrint() { std::cout << "staticPrint" << std::endl; }
int b;
public:
B(int i) : b{ i } {}
void print()
{
printFunc(b, staticPrint);
}
};
struct C
{
void operator()() { std::cout << "operator()" << std::endl; }
};
int main()
{
printFunc(1, testFunc);
A a{ 2 };
a.print();
B b{ 3 };
b.print();
printFunc(4, nullptr);
C c;
printFunc(5, c);
}
1 testFunc
2 privatePrint 2
3 staticPrint
4 f is null
5 operator()