2013-01-14 59 views
0

我想創建一個回調函數使用str :: tr1 ::函數指向一個公共成員函數。'不匹配'與成員回調函數使用std :: 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:根據n.m.和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

我把它'ABC :: mDBtoDScallback'是*不是*靜態類成員?函數試圖推導出一個'(ABC :: *)',你的函數對象並不期待(並且溫柔,偷看,我對C++ 11中的新函數對象及其流派並不特別感興趣,但這似乎(對我來說)成爲問題)。 – WhozCraig

+0

@WhozCraig:是的,看起來是正確的。 –

+0

這將是一件很好的事情,可以使用一個小型自包含示例。 –

回答

1

正如評論中所討論的,問題似乎是因爲你的函數對象期望一個靜態的非對象綁定函數,而你實際上將它傳遞給了一個成員。從我所看到的情況來看,有幾種解決方法,這是你可能已經考慮過的最簡單的方法;使用靜態並將對象的指針作爲參數傳遞。

或者,我不知道這是否適用於您的特定體系結構,但以下內容快速捕捉瞭如何使用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 :: function,std :: bind和std :: men_fn pony的std-lib專家完全準備好將其刪除提供更簡潔的解釋(或將此片段撕成碎片)。老實說,在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 
+0

謝謝你的解釋。我正在瀏覽cppreference.com頁面,確實很有趣。我的問題在於'dssCallBack'使用的回調簽名是在'dss'類型的類中定義的。儘管我明白爲什麼在這裏傳遞'this'這個重要信息,我無法改變這個簽名。將'dss'類回調綁定到'ABC'類是沒有意義的。無論如何,請不要刪除此響應,因爲它提供了有用的信息和示例。 –

+0

@ChinmayNerurkar好的。我會離開它。 Fwiw你不應該改變*函數*的簽名,而是改變傳遞給'std :: function <>'模板的* decl *。如果您可以靈活地更改*函數對象*的模板decl以及調用點(以傳遞object + params),那麼您可能會過去這一點。但是實際的成員函數聲明不需要這樣的改變(它已經有一個'* this'指針,其中的規定是開始所有這一切的開始,因爲它是非靜態的)。先生,祝你好運。 – WhozCraig

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應該是什麼?

這兩種解決方案是使用std::bind綁定this,或者通過this作爲參數,如std::mem_fn

+0

+1。先生,這些事情都很光滑。我花了一個半小時的時間來研究它們。旁邊的問題,我在評論中提到和我的答案(即將被刪除)中提到:這是否正確派遣到虛擬覆蓋?真的很好奇。 – WhozCraig

+0

調度如何? 'ABC :: mDBtoDScallback'是一個特定的函數 - 它沒有虛擬的或非虛擬的。除了'ABC :: mDBtoDScallback',它絕不會調用任何東西。我認爲。我其實不知道。 PTMF基本上對任何事都不好,所以我很少使用它們。 – Puppy

+0

@DeMdMG我明白爲什麼'this'在這裏很重要。但是,我無法更改'dssCallBack'的簽名,因爲它是在'dss'的類類型中定義的。我基本上需要從'ABC :: subs_rt'函數中調用'dssCallBack',並使'dssCallBack'從'ABC :: subs_rt'函數的參數中調用'raw_callback'。 'raw_callback'需要訪問'ABC'類的對象的私有成員,並將其作爲'ABC *'參數傳遞給它。 –

相關問題