0

パブリック メンバー関数を指す 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 の新しいものにも慣れてきました。

ありがとう。

編集: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;
}

コールバック自体は次のようになります

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::mDBtoDScallbackWhozCraig が推測したように、関数は静的ではありません。問題ありますか?この関数で使用されている変数の一部を静的にできません。これを回避する方法はありますか、それとも C スタイルの関数ポインターを使用する必要がありますか?

ありがとう。

EDIT 2 : nm および 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);
}

ありがとうございました。

4

2 に答える 2

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

this2 つの解決策は、 using をバインドするか、 のように引数としてstd::bind渡すことです。thisstd::mem_fn

于 2013-01-14T19:51:15.577 に答える
1

コメントで説明されているように、関数オブジェクトがオブジェクトにバインドされていない静的関数を期待しているのに、実際にはメンバーを渡しているため、問題が発生しているようです。私が見る限り、これにはいくつかの回避策がありますが、おそらくすでに検討している最も単純なものです。static を使用して、オブジェクトのポインターをパラメーターとして渡します。

または、これが特定のアーキテクチャで機能するかどうかはわかりませんが、 を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 の深さを真​​に理解している std-lib の専門家の 1 人がより簡潔な説明をポニーで作成した場合、私はそれを削除する準備ができています(または、このスニペットを細断します)。正直なところ、 SO のどこかに を介してメンバーを呼び出すより良いサンプルがあるかもしれませんが、私が言わなければならないwithstd::function<>の使用の単純さはかなり魅力的です。std::men_fn<>std::function<>


バーチャルディスパッチ

DeadMG のコメントを求めた後、仮想ディスパッチが機能するかどうか、私は本当に興味がありました。ポインターを提供しているので、これは良いチャンスだと思いましたがthis、息を止めていませんでしMyClass::CallMestd:::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
于 2013-01-14T19:39:24.023 に答える