【问题标题】:Using std::bind in template function parameter在模板函数参数中使用 std::bind
【发布时间】:2018-08-21 13:29:48
【问题描述】:

以前可能有人问过这个问题,但我找不到正确的搜索关键字。

在编写测试函数时,我决定将测试代码重构为模板函数:

#include <iostream>
#include <functional>
#include <utility>
#include <vector>

template <typename In, typename Exp >
void runTest (
    std::pair<In, Exp> testParams, 
    Exp (*testFunction)(In)
    /*std::function< Exp(In)> testFunction */ )
{
    Exp result = testFunction(testParams.first);
    std::cout   << "Result : " << (result == testParams.second? "SUCCESS":"FAILURE")
                << " expected : " << testParams.second 
                << " got : "  << result
                << std::endl;
}

用输入和预期结果填充一个向量,并将这些对与我们要测试的函数一起传递。非常适合一个功能:

long f1 (long a1)
{
    return a1 + 100;
}

void testf1()
{
    std::vector<std::pair<long, long> > testCases = {
        {100,200},
        {300,400}
    };
    for (auto test : testCases) {
        runTest (test, f1);
    }
}

但后来不得不测试一个需要两个参数的。 “好吧,没问题,我会 std::bind1st ......哦,那已经被弃用了...... std::bind 应该给它,对吧?第一个参数并将它传递给runTest”......

long f2 (long a1, long a2) 
{
    return a1+a2;
}

void testf2() 
{
    long a1 = 1234;
    std::vector<std::pair<long, long> > testCases = {
        {0,1234},
        {2,1238},
        {11,1245}
    };
    for (auto test : testCases){
        auto f2bound = std::bind(f2, a1, std::placeholders::_2);
        runTest (test, f2bound);
    }
}

但是the compiler says 'no'

~/src/cpplay/onestens$ g++ -m64 --std=c++11 -o soq.out soQuestionBind.cpp -g
soQuestionBind.cpp: In function ‘void testf2()’:
soQuestionBind.cpp:50:31: error: no matching function for call to ‘runTest(std::pair<long int, long int>&, std::_Bind<long int (*(long int, std::_Placeholder<2>))(long int, long int)>&)’
         runTest (test, f2bound);
                               ^
soQuestionBind.cpp:7:6: note: candidate: template<class In, class Exp> void runTest(std::pair<_T1, _T2>, Exp (*)(In))
 void runTest (
      ^
soQuestionBind.cpp:7:6: note:   template argument deduction/substitution failed:
soQuestionBind.cpp:50:31: note:   mismatched types ‘Exp (*)(In)’ and ‘std::_Bind<long int (*(long int, std::_Placeholder<2>))(long int, long int)>’
         runTest (test, f2bound);
                               ^

我有点落后于 C++11(以及 14 和 17),但这应该是可能的,对吧?

我猜 std::bind 返回的对象不能被强制转换成一个简单的函数指针......那么我的模板参数必须如何定义才能接受绑定函数?

【问题讨论】:

  • 为什么不简单地使用 lambda 函数呢? std::bind 有点过时了,因为我们有这些。
  • @πάνταῥεῖ 这意味着a1需要被捕获,然后没有函数指针:(

标签: c++ c++11 templates


【解决方案1】:

我猜 std::bind 返回的对象不能被强制转换成简单的函数指针。

正确。

获取通用可调用对象的典型方法是使用简单的模板参数。无需使用函数指针,std::function 或其他:

template <typename T, typename U, typename F>
void runTest (
    std::pair<T, U> testParams, 
    F testFunction )
{
    auto result = testFunction(testParams.first);
    // do something ...
}

现在您可以使用 std::bind,但我建议您改用 lambda。

【讨论】:

  • 谢谢。带有 lambda 的简单模板参数确实有效,但 std::bind 仍然无效。 '使用 lambda' 是对涉及bind 的任何问题的下意识反应,这有点烦人。 std::bind 具有可理解并记录在案的含义,而内联 lambda 可以做任何事情。
  • 关于 lambdas 的主题,它们的使用将如何影响模板专业化? lambdas 是否像普通函数一样“类型化”,由参数和返回类型定义?还是他们的捕获在打字中也起作用?我想知道编译器为runTest 生成了多少特化。
  • @veefu 哦,对。你应该使用__1,而不是__2。 Lambda 是具有重载调用运算符的类。 runTest 每种类型一次。
  • _1 做到了。再次感谢。
猜你喜欢
  • 1970-01-01
  • 2019-01-18
  • 2019-04-30
  • 2016-04-26
  • 1970-01-01
  • 1970-01-01
  • 2014-01-09
  • 2013-01-21
  • 2018-11-26
相关资源
最近更新 更多