简体   繁体   English

使用std :: tr1 :: function的成员回调函数出现“ No Match”错误

[英]'No Match' Errors with a member callback function using std::tr1::function

I am trying to create a callback function using str::tr1::function pointing to a public member function. 我正在尝试使用指向公共成员函数的str :: tr1 :: function创建回调函数。

std::tr1::function < int (const string& , const MessageInfo* , const void* , const int , const void* ) > dssCallBack;
dssCallBack = &ABC::mDBtoDScallback;

This callback will be passed to a function inside the body of another function of class ABC. 该回调将传递给ABC类的另一个函数体内的函数。 The signature of ABC::mDBtoDScallback is ABC::mDBtoDScallback的签名为

int DataserviceSubscriber::mDBtoDScallback(const string& strTopic, const MessageInfo* messageInfo, const void* data, const int dataLen, const void* callback_data)

When I try to compile this, I get the following error from g++. 当我尝试编译它时,我从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*]

I am trying to see what I am doing wrong here but cant spot it. 我试图查看我在这里做错了什么,但无法发现它。 I tried to look up but could not find others with similar issues. 我试图查找,但找不到其他存在类似问题的人。 I could use a C-style typedef but I wanted to use and keep things C++ style, in the process also getting used to some of the newer stuff in C++11. 我可以使用C风格的typedef,但我想使用并保留C ++风格,在此过程中还习惯了C ++ 11中的一些较新内容。

Thanks. 谢谢。

EDIT: As requested by Michael Burr, the call back is being called from a function as per the reference here http://en.cppreference.com/w/cpp/utility/functional/function 编辑:根据迈克尔·伯尔(Michael Burr)的要求,正在从函数中调用回调,方法是参考此处的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;
}

The callback itself looks like 回调本身看起来像

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
    }
}

The function int ABC::mDBtoDScallback is not static as WhozCraig guessed. 正如WhozCraig猜测的那样,函数int ABC::mDBtoDScallback不是静态的。 Is that a problem? 那是问题吗? I can't make some of the variables used in this function static. 我不能使此函数中使用的某些变量静态化。 Is there any way around this or do I have to use a C-style function pointer? 有什么解决办法还是必须使用C样式的函数指针?

Thanks. 谢谢。

EDIT 2 : As per nm and WhozCraig's concern and per this link C++: Assigning a function to a tr1::function object 编辑2:根据nm和WhozCraig的关注以及此链接, C ++:将函数分配给tr1 :: function对象

I changed the lines in ABC::subs_rt function to 我将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);

I tried the commented and the uncommented option but I get this error now 我尝试了注释和未注释的选项,但是现在出现此错误

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

RESOLUTION OF ISSUE: Given my requirements decided to make my callback a static member function and pass a pointer to the parent class object through the const void* callback_data . 问题的解决方案:鉴于我的要求,决定将我的回调设为静态成员函数,并通过const void* callback_data传递指向父类对象的指针。 Being a static function it can access private functions of the class ABC and pass parameters to raw_callback . 作为静态函数,它可以访问ABC类的私有函数并将参数传递给raw_callback The help I got from all the comments was a big learning experience for me and eventually led me down towards the solution. 我从所有评论中获得的帮助对我来说是一次很好的学习经历,最终使我走向了解决方案。

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);
}

Thank you. 谢谢。

The source is simple, if you know where to look. 如果您知道要查找的位置,则源很简单。 Consider the following code: 考虑以下代码:

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);

What is this ? 什么是this You never provided it. 您从未提供过。 So there's no way that std::function could possibly make this work- you're trying to invoke a member but did not provide an object. 因此, std::function不可能完成这项工作-您正在尝试调用成员,但未提供对象。 What is std::function supposed to do, magically decide what this should be? 什么是std::function应该做的,神奇地决定什么this应该是什么?

The two solutions are, bind a this using std::bind , or pass this as an argument, as in std::mem_fn . 将两种溶液是,绑定this使用std::bind ,或通过this作为参数,如在std::mem_fn

As discussed in comments, the issue appears to be because your function object is expecting a static non-object-bound function, while you're actually passing it a member. 正如评论中所讨论的,问题似乎是因为您的函数对象实际上是一个静态的,非对象绑定的函数,而实际上却是将其传递给成员。 From what I can see, there are several work-arounds for this, the simplest one you probably already are considering; 据我所知,有几种解决方法,您可能已经在考虑最简单的解决方法。 using a static and pass your object's pointer as a parameter. 使用静态并将对象的指针作为参数传递。

Alternatively, I don't know if this will work for your particular architecture, but the following was quickly snapped together on how to invoke a member function with a specified object using an std::mem_fn<> in conjunction with a std::function<> . 另外,我不知道这是否适用于您的特定体系结构,但是以下内容很快就结合在一起,说明如何使用std::mem_fn<>std::function<> std::mem_fn<>使用指定对象调用成员std::function<> This is a stand-alone sample but I hope you can see how it may assist you. 这是一个独立的示例,但我希望您能看到它对您有何帮助。

#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;
}

Output 输出量

Invoking CallMe with 0x7fff5fbff7d8 object...
CallMe fired : 0x7fff5fbff7d8 !

Invoking CallMe with 0x7fff5fbff7d0 object...
CallMe fired : 0x7fff5fbff7d0 !

Note 注意

The read on how member function objects work, provided in C++11, on cppreference.com is fascinating to me. cppreference.com上C ++ 11中提供的有关成员函数对象如何工作的内容吸引我。 Not that anyone really cares about that.I have no idea if they properly dispatch to virtuals, etc, but I'm absolutely amazed by them. 并不是每个人都真正在乎这一点,我不知道他们是否正确地将其分配给虚拟机等,但我对此感到非常惊讶。

I hope you find this helpful, but I'm fully prepared to delete it if one of the std-lib experts that truly understands the depths of std::function, std::bind, and std::men_fn pony up more concise explanations (or rips this snippet to shreds). 希望对您有所帮助,但是如果一位真正了解std :: function,std :: bind和std :: men_fn深度知识的std-lib专家之一,我已经准备好删除它,以进行更简洁的解释(或将该片段撕成碎片)。 Honestly, there are probably better samples on SO somewhere on invoking members through std::function<> , but the simplicity of using std::men_fn<> with std::function<> I have to say is rather captivating. 坦白地说,在通过std::function<>调用成员的SO上可能有更好的示例,但是我要说的将std::men_fn<>std::function<>一起使用的简单性颇具吸引力。


Virtual Dispatch 虚拟派遣

After seeking DeadMG's comment I was genuinely curious if virtual dispatching worked. 在征求DeadMG的意见后,我真的很好奇虚拟调度是否有效。 I thought it stood a good chance, since we're providing a this pointer, but was not holding my breath, since clearly we pass the MyClass::CallMe member by-address to the constructor of our std:::mem_fn<> . 我认为这是个很好的机会,因为我们提供了this指针,但没有屏住呼吸,因为显然我们将MyClass::CallMe成员的副地址传递给了std:::mem_fn<>的构造函数。

The updated source, and resulting run, were interesting. 更新的源代码以及由此产生的运行非常有趣。 Notice the same function object used in both instances. 注意两个实例中使用的相同功能对象。 Whether it is intended to work this way (and it appears to, btw) I cannot say, but it was interesting to me, none-the-less. 我不能说是否打算以这种方式工作(顺便说一句),但这对我很有趣,尽管如此。

#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;
}

Output 输出量

Invoking CallMe with 000000000021FB58 object...
MyClass::CallMe fired : 000000000021FB58
Invoking CallMe with 000000000021FB78 object...
MyDerived::CallMe fired : 000000000021FB78

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM