Using a template callback function in C++

15.5k Views Asked by At

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.

2

There are 2 best solutions below

1
On

Using a functor template will solve your issues:

template< typename Functor, typename ParamType >
void DoSmth(Functor isGood, const ParamType param){
   //...
   if(isGood(param, some_int_calculated_here)) doSmthElse();
}

Now you can use any function or functor object that has a compatible signature(not necessarily one that takes a ParamType and an int as parameters). Otherwise, you'll need to use functions with that exact signature.

0
On

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)) { ...
}