web-dev-qa-db-ja.com

std :: functionおよびstd :: bindを使用すると、テンプレート引数の推論/置換に失敗しました

テンプレートメンバー関数でstd :: functionを使用すると、コンパイルエラーが発生します。次のコードは簡単な例です。

#include <functional>
#include <memory>
using std::function;
using std::bind;
using std::shared_ptr;

class Test {
public:
     template <typename T>
     void setCallback(function<void (T, int)> cb); 
};

template <typename T>
void Test::setCallback(function<void (T, int)> cb)
{
    // do nothing
}

class TestA {
public:
    void testa(int a, int b) {   }
};


int main()
{
    TestA testA;
    Test test;
    test.setCallback(bind(&TestA::testa, &testA, std::placeholders::_1, std::placeholders::_2));
    return 0;
}

また、次のコンパイルエラーが発生します。

testtemplate.cpp:関数「int main()」内:

testtemplate.cpp:29:92:エラー: 'Test :: setCallback(std :: _ Bind_helper)(int、int)、TestA、const std :: _ Placeholder <1>&、const std :: _ Placeholderへの呼び出しに一致する関数がありません<2>&> :: type) '

testtemplate.cpp:29:92:注:候補は:testtemplate.cpp:10:7:注:テンプレートvoid Test :: setCallback(std :: function)

testtemplate.cpp:10:7:注:テンプレート引数の推論/置換に失敗しました:

testtemplate.cpp:29:92:注:「std :: _ Bind(TestA *、std :: _ Placeholder <1>、std :: _ Placeholder <2>)>」は「std :: function」から派生したものではありません

C++ 11とg ++ 4.7を使用しています

22
haipeng31

問題を理解するために、別々のステートメントを聞かせてください:

auto f = bind(&TestA::testa, &testA, _1, _2); // OK
test.setCallback(f);                          // <<--- Error is here

setCallbackTの型を知る必要があり、fから推測できないため、型を与えます

test.setCallback<TYPE>(f); // TYPE: int, float, a class, ...
11
deepmax

次のいくつかのバリアントを使用して、型の推論を機能させることができます。

template<typename CALLBACK>
void setCallback(CALLBACK cb) {
  typedef CALLBACK::first_argument_type T;
  static_assert(is_same_type<CALLBACK,function<void(T,int)>>::value);
  ...
}

このように、CALLBACKは引数を見ることで決定できます。 bindが実際にstd :: functionを返さず、むしろ1つとしてキャストできるものを返す場合、問題が発生する可能性があります。よく分かりません。

0
dspeyer