【问题标题】:template argument deduction/substitution failed, when using std::function and std::bind使用 std::function 和 std::bind 时模板参数推导/替换失败
【发布时间】:2013-03-10 16:01:51
【问题描述】:

在模板化成员函数中使用 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, 常量 std::_Placeholder&, 常量 std::_Placeholder&>::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, std::_Placeholder)>' 不是从'std::function' 派生的

我使用的是 C++11 和 g++ 4.7

【问题讨论】:

  • test.setCallback&lt;int&gt;(bind...)bind 的结果不是std::function,所以没有参数推导。
  • 请告诉我你认为编译器是如何推断出T 的。
  • @Xeo 我是模板的大一新生,不知道dedece T 是如何工作的。一些材料有帮助吗?
  • @user1679133:一般情况下,当std::function 是参数时,除非您传递std::function,否则您必须完整地拼出类型。
  • Lambdas 是比 std::bind 更好的选择

标签: c++ function templates bind


【解决方案1】:

要找出问题,请分开声明:

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, ...

【讨论】:

  • 模板太难了,我用了一个下午的时间来处理这个问题,最后还是无法解决,谢谢你的解释。对了,你能给我一些关于学习模板的建议吗
  • @user1679133:每天编程和练习,这是学习编程概念的唯一途径。我们都是这样做的。并阅读 Stackoverflow 的问答。
【解决方案2】:

您可以使用以下变体进行类型推断:

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 而是可以转换为一个的东西,它可能会遇到麻烦。我不确定。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-01-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多