Я пытаюсь создать функцию обратного вызова, используя 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*]
Я пытаюсь понять, что я делаю не так, но не могу это заметить. Я попытался найти, но не смог найти других с похожими проблемами. Я мог бы использовать typedef в стиле C, но я хотел использовать и сохранять стиль 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 ++: назначение функции объекту tr1 :: function
Я изменил строки в функции 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);
}
Спасибо.
Как уже говорилось в комментариях, проблема заключается в том, что ваш функциональный объект ожидает статическую функцию, не связанную с объектом, в то время как вы фактически передаете ей член. Из того, что я вижу, есть несколько обходных путей, самый простой из которых вы, вероятно, уже рассматриваете; используя статические и передать указатель вашего объекта в качестве параметра.
В качестве альтернативы, я не знаю, будет ли это работать для вашей конкретной архитектуры, но ниже было быстро показано, как вызывать функцию-член с указанным объектом, используя std::mem_fn<>
в сочетании с std::function<>
, Это отдельный образец, но я надеюсь, что вы увидите, как он может вам помочь.
#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, найдет более краткие пояснения. (или разрывает этот фрагмент в клочья). Честно говоря, есть где-то лучшие образцы на SO, когда вы вызываете участников через std::function<>
, но простота использования std::men_fn<>
с std::function<>
Скажу сразу, это довольно увлекательно.
Виртуальная рассылка
После поиска комментариев DeadMG мне было искренне любопытно, работает ли виртуальная диспетчеризация. Я думал, что это хороший шанс, так как мы предоставляем this
указатель, но не затаил дыхание, так как явно мы проходим MyClass::CallMe
адрес участника к конструктору нашего 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;
}
Выход
Invoking CallMe with 000000000021FB58 object...
MyClass::CallMe fired : 000000000021FB58
Invoking CallMe with 000000000021FB78 object...
MyDerived::CallMe fired : 000000000021FB78
Источник прост, если вы знаете, где искать. Рассмотрим следующий код:
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
,