Using a template callback function in C++

Flamefire picture Flamefire · Aug 23, 2013 · Viewed 12k times · Source

I want to have a function that checks certain conditions based on a given callback function.

Considers this code:

class Foo{
template <class ParamType>
struct IsGood
{
    typedef bool (*Check)(typename const ParamType*, int other);
};
template< typename ParamType >
void DoSmth(IsGood<ParamType>::Check isGood, const ParamType* param){
   //...
   if(isGood(param, some_int_calculated_here)) doSmthElse();
}

What I want is to call it with:

bool checkEqualInt(int* i, int j){return *i==j;}
bool checkEqualFloat(float* i, float j){return *i==j;}

DoSmth(checkEqualInt, &i);
DoSmth(checkEqualFloat, &i_float);

(All constructed examples to show the problem)

The compiler won't get that and throws me error C2664 "converting param 1 from bool(int*,int) in bool(ParamType,int) not possible"

I there a solution without using

template< typename ParamType, Check >
void DoSmth(Check isGood, const ParamType param)

Which ommits the necessary declaration of the check function?

Best solution would be to get the IsGood() header in the function itself.

Answer

David Rodr&#237;guez - dribeas picture David Rodríguez - dribeas · Aug 23, 2013

The problem is that the first argument of your template function is not deducible:

template< typename ParamType >
void DoSmth(typename IsGood<ParamType>::Check isGood, const ParamType param)
//          ^        ^^^^^^^^^^^^^^^^^^^^^^^^
//          missing  nested type! not deducible!

The simple option is to expand the signature in place (C++03,C++11):

template< typename ParamType >
void DoSmth(void (*isGood)(ParamType,int), const ParamType param)
// note: dropped 'const' that will be dropped anyway by the compiler

Or if you have C++11 you can substitute the IsGood<ParamType>::Check by a template alias:

template <typename T>
using IsGood = void (*)(T,int);
template< typename ParamType >
void DoSmth(IsGood<ParamType> isGood, const ParamType param)

Or alternatively refactor your code to take a functor that will make it more flexible, simple and possibly efficient since there will be easier for the compiler to inline the call:

template <typename P, typename T>
void DoSmth(P predicate, T param) {
   if (predicate(param,somethingelse)) { ...
}