5

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.

Flamefire
  • 5,313
  • 3
  • 35
  • 70
  • I didn't see that last line before answering. Why is it that using a template parameter that represents a functor is not an option? – mfontanini Aug 23 '13 at 19:29
  • 2
    Works for me: http://ideone.com/czNr1e (after adding/removing `typename` where necessary). – user2093113 Aug 23 '13 at 19:31
  • @user2093113 `checkEqualFloat` won't work though. – mfontanini Aug 23 '13 at 19:39
  • 1
    @mfontanini Indeed, but that is because `checkEqualFloat` as specified in the question doesn't match the `IsGood::Check` function signature. Correcting the signature to take an `int` as the second parameter works: http://ideone.com/vx6ao8. – user2093113 Aug 23 '13 at 19:46
  • @user2093113: Your code is working. I just forgot something: The ParamTypes are given as pointers. I updated the question. Sorry for that. I thought it got to be the same. It works However with ommitting pointers in IsGood and use "DoSmth(IsGood::Check" But it looks strange – Flamefire Aug 25 '13 at 16:43

2 Answers2

4

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)) { ...
}
David Rodríguez - dribeas
  • 204,818
  • 23
  • 294
  • 489
3

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.

mfontanini
  • 21,410
  • 4
  • 65
  • 73
  • As mentioned, I wanted to avoid the functor to specify the function signature in the function header itself – Flamefire Aug 25 '13 at 16:35