我正在尝试使用指向公共成员函数的str :: tr1 :: function创建一个回调函数。
std::tr1::function < int (const string& , const MessageInfo* , const void* , const int , const void* ) > dssCallBack;
dssCallBack = &ABC::mDBtoDScallback;
此回调将传递给ABC类的另一个函数体内的函数。 ABC::mDBtoDScallback
的签名是
int DataserviceSubscriber::mDBtoDScallback(const string& strTopic, const MessageInfo* messageInfo, const void* data, const int dataLen, const void* callback_data)
当我尝试编译时,我从g ++中得到以下错误。
In file included from /usr/lib/gcc/x86_64-redhat-linux/4.4.6/../../../../include/c++/4.4.6/tr1/functional:56,
from ../src/bmrk/databus/ABC.hpp:17,
from ../src/bmrk/databus/ABC.cpp:1:
/usr/lib/gcc/x86_64-redhat-linux/4.4.6/../../../../include/c++/4.4.6/tr1_impl/functional: In static member function ‘static _Res std::tr1::_Function_handler<_Res(_ArgTypes ...), _Member _Class::*>::_M_invoke(const std::tr1::_Any_data&, _ArgTypes ...) [with _Class = ABC, _Member = int(const std::string&, const MessageInfo*, const void*, int, const void*), _Res = int, _ArgTypes = const std::string&, const MessageInfo*, const void*, int, const void*]’:
/usr/lib/gcc/x86_64-redhat-linux/4.4.6/../../../../include/c++/4.4.6/tr1_impl/functional:2005: instantiated from ‘std::tr1::function<_Res(_ArgTypes ...)>::function(_Functor, typename __gnu_cxx::__enable_if<(! std::tr1::is_integral::value), std::tr1::function<_Res(_ArgTypes ...)>::_Useless>::__type) [with _Functor = int (ABC::*)(const std::string&, const MessageInfo*, const void*, int, const void*), _Res = int, _ArgTypes = const std::string&, const MessageInfo*, const void*, int, const void*]’
/usr/lib/gcc/x86_64-redhat-linux/4.4.6/../../../../include/c++/4.4.6/tr1_impl/functional:1885: instantiated from ‘typename __gnu_cxx::__enable_if<(! std::tr1::is_integral::value), std::tr1::function<_Res(_ArgTypes ...)>&>::__type std::tr1::function<_Res(_ArgTypes ...)>::operator=(_Functor) [with _Functor = int (ABC::*)(const std::string&, const MessageInfo*, const void*, int, const void*), _Res = int, _ArgTypes = const std::string&, const MessageInfo*, const void*, int, const void*]’
../src/bmrk/databus/dataservice_subscriber.cpp:266: instantiated from here
/usr/lib/gcc/x86_64-redhat-linux/4.4.6/../../../../include/c++/4.4.6/tr1_impl/functional:1714: error: no match for call to ‘(std::tr1::_Mem_fn<int (ABC::*)(const std::string&, const MessageInfo*, const void*, int, const void*)>) (const std::basic_string<char, std::char_traits<char>, std::allocator<char> >&, const MessageInfo*&, const void*&, int&, const void*&)’
/usr/lib/gcc/x86_64-redhat-linux/4.4.6/../../../../include/c++/4.4.6/tr1_impl/functional:546: note: candidates are: _Res std::tr1::_Mem_fn<_Res (_Class::*)(_ArgTypes ...)>::operator()(_Class&, _ArgTypes ...) const [with _Res = int, _Class = ABC, _ArgTypes = const std::string&, const MessageInfo*, const void*, int, const void*]
/usr/lib/gcc/x86_64-redhat-linux/4.4.6/../../../../include/c++/4.4.6/tr1_impl/functional:551: note: _Res std::tr1::_Mem_fn<_Res (_Class::*)(_ArgTypes ...)>::operator()(_Class*, _ArgTypes ...) const [with _Res = int, _Class = ABC, _ArgTypes = const std::string&, const MessageInfo*, const void*, int, const void*]
我想看看我在这里做错了什么但是无法发现它。我试图抬头但找不到其他有类似问题的人。我可以使用C风格的typedef但是我想使用并保持C ++风格,在这个过程中也习惯了C ++ 11中的一些新东西。
感谢。
编辑:根据迈克尔·伯尔的要求,根据此处的参考http://en.cppreference.com/w/cpp/utility/functional/function
从一个函数调用回调int ABC::subs_rt(const vector<string> &symbols, raw_callback_t raw_callback, void *app_data, Error *error)
{
DBtoDS_callback_data cbData;
cbData.subscriber_callback = raw_callback;
cbData.raw_callback_app_data = app_data;
cbData.err = error;
// Perform processing on 'symbols'
// dss is a member of class ABC and has been initialized in constructor
dss->AddSubscriptionPrefix(symbols);
b_cancel_subscription = false;
std::tr1::function < int (const string& , const MessageInfo* , const void* , const int , const void* ) > dssCallBack;
dssCallBack = &DataserviceSubscriber::mDBtoDScallback;
dss->Subscribe(dssCallBack, static_cast<const void*>(&cbData));
return 0;
}
回调本身就像
int ABC::mDBtoDScallback(const string& strTopic, const MessageInfo* messageInfo, const void* data, const int dataLen, const void* callback_data)
{
const DBtoDS_callback_data* cbData = static_cast<const DBtoDS_callback_data*>(callback_data);
if(0 == messageInfo) // Version 1
{
// Do callback Stuff
}
else // Version 2
{
Subscriber::timeval_t now;
TimeUtils::now(now);
std::string payload(static_cast<const char*>(data), dataLen);
// Do callback Stuff
}
}
函数int ABC::mDBtoDScallback
不是静态的,因为WhozCraig猜到了。那是问题吗?我不能在这个函数中使用一些静态的变量。有没有办法解决这个问题,还是我必须使用C风格的函数指针?
感谢。
编辑2:按照惯例。和WhozCraig的关注点和{链接C++: Assigning a function to a tr1::function object
我将ABC :: subs_rt函数中的行更改为
std::tr1::function < int (const string& , const MessageInfo* , const void* , const int , const void* ) > dssCallBack;
//dssCallBack = std::tr1::bind(&ABC::mDBtoDScallback, this, std::tr1::placeholders::_1);
dssCallBack = std::tr1::bind(&ABC::mDBtoDScallback, this);
我尝试了评论和未评论的选项,但我现在收到此错误
In file included from /usr/lib/gcc/x86_64-redhat-linux/4.4.6/../../../../include/c++/4.4.6/tr1/functional:56,
from ../src/bmrk/databus/ABC.hpp:17,
from ../src/bmrk/databus/ABC.cpp:1:
/usr/lib/gcc/x86_64-redhat-linux/4.4.6/../../../../include/c++/4.4.6/tr1_impl/functional: In member function ‘typename std::tr1::result_of<_Functor(typename std::tr1::result_of<std::tr1::_Mu<_Bound_args, std::tr1::is_bind_expression::value, (std::tr1::is_placeholder::value > 0)>(_Bound_args, std::tr1::tuple<_UElements ...>)>::type ...)>::type std::tr1::_Bind<_Functor(_Bound_args ...)>::__call(const std::tr1::tuple<_UElements ...>&, std::tr1::_Index_tuple<_Indexes ...>) [with _Args = const std::basic_string<char, std::char_traits<char>, std::allocator<char> >&, const MessageInfo*&, const void*&, int&, const void*&, int ..._Indexes = 0, _Functor = std::tr1::_Mem_fn<int (ABC::*)(const std::string&, const MessageInfo*, const void*, int, const void*)>, _Bound_args = ABC*]’:
/usr/lib/gcc/x86_64-redhat-linux/4.4.6/../../../../include/c++/4.4.6/tr1_impl/functional:1191: instantiated from ‘typename std::tr1::result_of<_Functor(typename std::tr1::result_of<std::tr1::_Mu<_Bound_args, std::tr1::is_bind_expression::value, (std::tr1::is_placeholder::value > 0)>(_Bound_args, std::tr1::tuple<_UElements ...>)>::type ...)>::type std::tr1::_Bind<_Functor(_Bound_args ...)>::operator()(_Args& ...) [with _Args = const std::basic_string<char, std::char_traits<char>, std::allocator<char> >, const MessageInfo*, const void*, int, const void*, _Functor = std::tr1::_Mem_fn<int (ABC::*)(const std::string&, const MessageInfo*, const void*, int, const void*)>, _Bound_args = ABC*]’
/usr/lib/gcc/x86_64-redhat-linux/4.4.6/../../../../include/c++/4.4.6/tr1_impl/functional:1654: instantiated from ‘static _Res std::tr1::_Function_handler<_Res(_ArgTypes ...), _Functor>::_M_invoke(const std::tr1::_Any_data&, _ArgTypes ...) [with _Res = int, _Functor = std::tr1::_Bind<std::tr1::_Mem_fn<int (ABC::*)(const std::string&, const MessageInfo*, const void*, int, const void*)>(ABC*)>, _ArgTypes = const std::string&, const MessageInfo*, const void*, int, const void*]’
/usr/lib/gcc/x86_64-redhat-linux/4.4.6/../../../../include/c++/4.4.6/tr1_impl/functional:2005: instantiated from ‘std::tr1::function<_Res(_ArgTypes ...)>::function(_Functor, typename __gnu_cxx::__enable_if<(! std::tr1::is_integral::value), std::tr1::function<_Res(_ArgTypes ...)>::_Useless>::__type) [with _Functor = std::tr1::_Bind<std::tr1::_Mem_fn<int (ABC::*)(const std::string&, const MessageInfo*, const void*, int, const void*)>(ABC*)>, _Res = int, _ArgTypes = const std::string&, const MessageInfo*, const void*, int, const void*]’
/usr/lib/gcc/x86_64-redhat-linux/4.4.6/../../../../include/c++/4.4.6/tr1_impl/functional:1885: instantiated from ‘typename __gnu_cxx::__enable_if<(! std::tr1::is_integral::value), std::tr1::function<_Res(_ArgTypes ...)>&>::__type std::tr1::function<_Res(_ArgTypes ...)>::operator=(_Functor) [with _Functor = std::tr1::_Bind<std::tr1::_Mem_fn<int (ABC::*)(const std::string&, const MessageInfo*, const void*, int, const void*)>(ABC*)>, _Res = int, _ArgTypes = const std::string&, const MessageInfo*, const void*, int, const void*]’
../src/bmrk/databus/ABC.cpp:266: instantiated from here
/usr/lib/gcc/x86_64-redhat-linux/4.4.6/../../../../include/c++/4.4.6/tr1_impl/functional:1137: error: no match for call to ‘(std::tr1::_Mem_fn<int (ABC::*)(const std::string&, const MessageInfo*, const void*, int, const void*)>) (ABC*&)’
/usr/lib/gcc/x86_64-redhat-linux/4.4.6/../../../../include/c++/4.4.6/tr1_impl/functional:546: note: candidates are: _Res std::tr1::_Mem_fn<_Res (_Class::*)(_ArgTypes ...)>::operator()(_Class&, _ArgTypes ...) const [with _Res = int, _Class = ABC, _ArgTypes = const std::string&, const MessageInfo*, const void*, int, const void*]
/usr/lib/gcc/x86_64-redhat-linux/4.4.6/../../../../include/c++/4.4.6/tr1_impl/functional:551: note: _Res std::tr1::_Mem_fn<_Res (_Class::*)(_ArgTypes ...)>::operator()(_Class*, _ArgTypes ...) const [with _Res = int, _Class = ABC, _ArgTypes = const std::string&, const MessageInfo*, const void*, int, const void*]
make[1]: *** [ABC.lo] Error 1
问题的解决方案:鉴于我的要求决定使我的回调成为静态成员函数,并通过const void* callback_data
将指针传递给父类对象。作为静态函数,它可以访问ABC类的私有函数并将参数传递给raw_callback
。我从所有评论中得到的帮助对我来说是一次很大的学习经历,并最终导致我走向解决方案。
static int ABC::mDBtoDScallback(const string& strTopic, const MessageInfo* messageInfo, const void* data, const int dataLen, const void* callback_data)
{
const DBtoDS_callback_data* cbData = static_cast<const DBtoDS_callback_data*>(callback_data);
TimeUtils::now(now);
std::string payload(static_cast<const char*>(data), dataLen);
string symbol;
string sym;
int pri_s = 0;
if(0 == messageInfo)
{
parse_topic(strTopic, symbol, pri_s, cbData->err);
}
else
{
symbol = messageInfo->key();
pri_s = ( messageInfo->has_pri_s() ? messageInfo->pri_s() : 0 );
}
if (cbData->subs->symbols_need_translation())
{
cbData->subs->translate_symbol(cbData->subs->_translator, symbol, sym, false);
}
else
{
sym = symbol;
}
cbData->subscriber_callback(cbData->subs, sym, pri_s, cbData->subs->prod, payload, now, cbData->raw_callback_app_data, cbData->err);
}
谢谢。
答案 0 :(得分:2)
如果你知道在哪里看,那么来源很简单。请考虑以下代码:
std::tr1::function < int (const string& , const MessageInfo* , const void* , const int , const void* ) > dssCallBack;
dssCallBack = &ABC::mDBtoDScallback;
dssCallBack(std::string(), nullptr, nullptr, 0, nullptr);
什么是this
?你从来没有提供它。所以std::function
无法使这项工作成为可能 - 你试图调用一个成员但没有提供一个对象。什么是std::function
应该做的,神奇地决定this
应该是什么?
这两个解决方案是,使用this
绑定std::bind
,或将this
作为参数传递,如std::mem_fn
中所述。
答案 1 :(得分:1)
正如评论中所讨论的那样,问题似乎是因为你的函数对象期望一个静态的非对象绑定函数,而你实际上是在传递一个成员。从我所看到的,有几个解决方案,这是你可能已经考虑过的最简单的一个;使用静态并将对象的指针作为参数传递。
或者,我不知道这是否适用于您的特定体系结构,但以下内容很快就是如何使用std::mem_fn<>
和{{std::function<>
一起调用具有指定对象的成员函数的。 1}}。这是一个独立的样本,但我希望你能看到它对你的帮助。
#include <iostream>
#include <functional>
using namespace std;
class MyClass
{
public:
MyClass() {}
int CallMe(void *p, int a, float f)
{
// use params herere
cout << "CallMe fired : " << this << " !\n" << endl;
return 0;
}
};
int main()
{
MyClass obj, obj2;
std::function<int(MyClass*,void*,int,float)> fn(std::mem_fn(&MyClass::CallMe));
cout << "Invoking CallMe with " << &obj << " object..." << endl;
fn(&obj, NULL, 1, 2.0);
cout << "Invoking CallMe with " << &obj2 << " object..." << endl;
fn(&obj2, NULL, 1, 2.0);
return 0;
}
<强>输出强>
Invoking CallMe with 0x7fff5fbff7d8 object...
CallMe fired : 0x7fff5fbff7d8 !
Invoking CallMe with 0x7fff5fbff7d0 object...
CallMe fired : 0x7fff5fbff7d0 !
注意强>
关于成员函数对象如何工作的阅读,在C ++ 11中提供,cppreference.com对我来说是引人入胜的。并不是说有人真正关心它。我不知道他们是否正确地发送到虚拟机等,但我对它们感到惊讶。
我希望你觉得这很有帮助,但是我完全准备删除它,如果其中一个std-lib专家真正了解std :: function,std :: bind和std :: men_fn pony的深度更简洁的解释(或将这个片段撕成碎片)。老实说,在通过std::function<>
调用成员的某个地方可能有更好的样本,但使用std::men_fn<>
与std::function<>
的简单性我不得不说是相当迷人。
虚拟调度
在寻求DeadMG的评论之后,如果虚拟调度有效,我真的很好奇。我认为这是一个很好的机会,因为我们提供了一个this
指针,但没有屏住呼吸,因为很明显我们将MyClass::CallMe
成员的地址传递给我们{{1}的构造函数}}。
更新的源代码和最终的运行很有意思。注意两个实例中使用的相同函数对象。无论是打算以这种方式工作(而且似乎,顺便说一句),我都说不出来,但对我来说这很有意思,不过没有。
std:::mem_fn<>
<强>输出强>
#include <iostream>
#include <functional>
using namespace std;
class MyClass
{
public:
MyClass() {}
virtual int CallMe(void *p, int a, float f)
{
// use params herere
cout << "MyClass::CallMe fired : " << this << endl;
return 0;
}
};
class MyDerived : public MyClass
{
public:
MyDerived() {}
virtual int CallMe(void *p, int a, float f)
{
// use params herere
cout << "MyDerived::CallMe fired : " << this << endl;
return 0;
}
};
int main()
{
MyClass obj;
MyDerived obj2;
std::function<int(MyClass*,void*,int,float)> fn(std::mem_fn(&MyClass::CallMe));
cout << "Invoking CallMe with " << &obj << " object..." << endl;
fn(&obj, NULL, 1, 2.0);
cout << "Invoking CallMe with " << &obj2 << " object..." << endl;
fn(&obj2, NULL, 1, 2.0);
return 0;
}