Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using a template callback function in C++

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.

like image 449
Flamefire Avatar asked Aug 23 '13 19:08

Flamefire


People also ask

How do you write a callback function in C?

We can define it in other words like this: If the reference of a function is passed to another function argument for calling, then it is called the callback function. In C we have to use the function pointer to call the callback function. The following code is showing how the callback function is doing its task.

Can we use template in main function?

main cannot be a function template; it must be a function.

What is a function template in C?

Function templates. Function templates are special functions that can operate with generic types. This allows us to create a function template whose functionality can be adapted to more than one type or class without repeating the entire code for each type.

Do we have template in C?

The main type of templates that can be implemented in C are static templates. Static templates are created at compile time and do not perform runtime checks on sizes, because they shift that responsibility to the compiler.


2 Answers

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)) { ...
}
like image 177
David Rodríguez - dribeas Avatar answered Oct 02 '22 14:10

David Rodríguez - dribeas


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.

like image 45
mfontanini Avatar answered Oct 02 '22 15:10

mfontanini