mardi 21 août 2018

Using std::bind in template function parameter

This has probably been asked in some way before, but I cannot find the right search keywords.

While writing testing functions, I decided to refactor the testing code into a template function:

#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;
}

Fill a vector with input and expected results and pass the pairs along with the function we want to test. Worked great for one function:

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);
    }
}

but then had to test one that takes two parameters. "Ok, no problem, I'll std::bind1st... oh, that's deprecated... std::bind should to it though, right? the first argument and pass that along to 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);
    }
}

But 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);
                               ^

I'm a bit behind C++11 (and 14 and 17) but this should be possible, right?

I guess the object returned by std::bind couldn't be coerced into a simple function pointer... so how must my template parameter be defined to accept the bound function?

Aucun commentaire:

Enregistrer un commentaire