28

テンプレート化されたメンバー関数で 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)'</p>

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' から派生したものではありません</p >

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

4

2 に答える 2

15

問題を理解するには、ステートメントを分けてみましょう。

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

setCallbackは の型を知る必要がTあり、 から推測できないfため、型を指定します

test.setCallback<TYPE>(f); // TYPE: int, float, a class, ...
于 2013-03-21T08:44:53.483 に答える
1

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

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つとしてキャストできるものを返すと、問題が発生する可能性があります。わからない。

于 2013-03-21T18:28:23.597 に答える