在C++中使用模板回调函数

5

我希望有一个函数,根据给定的回调函数检查某些条件。

考虑以下代码:

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

我想要的是这样调用它:

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

(所有构造的示例均用于展示问题)

编译器无法理解并抛出错误C2664“将参数1从bool(int *,int)转换为bool(ParamType,int)不可能”。

有没有不使用的解决方案

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

哪个省略了check函数的必要声明?

最好的解决方案是在函数本身中获得IsGood()头。


回答之前我没有看到最后一行。为什么不能使用代表函数对象的模板参数呢? - mfontanini
2
对我来说可以运行:http://ideone.com/czNr1e(在必要时添加/删除`typename`)。 - user2093113
@user2093113 checkEqualFloat 不会起作用。 - mfontanini
1
@mfontanini确实如此,但这是因为问题中指定的checkEqualFloatIsGood<float> :: Check函数签名不匹配。将签名更正为以“int”作为第二个参数的函数即可解决:http://ideone.com/vx6ao8。 - user2093113
@user2093113:你的代码已经可以运行了。我只是忘记了一些东西:ParamTypes被给定为指针。 我更新了问题。对此我很抱歉。我以为它应该是一样的。 如果在IsGood中省略指针并使用"DoSmth(IsGood<ParamType*>::Check)",它仍然可以工作。但这看起来很奇怪。 - Flamefire
2个回答

4

问题在于您的模板函数的第一个参数无法被推断出:

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

简单的方法是在原地扩展签名(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

如果您使用的是C++11,可以通过使用模板别名来替换IsGood<ParamType>::Check

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

或者,您可以重构代码以采用函数对象,这将使其更加灵活、简单,并可能更加高效,因为编译器更容易内联调用:

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

3
使用函数对象模板可以解决您的问题:
template< typename Functor, typename ParamType >
void DoSmth(Functor isGood, const ParamType param){
   //...
   if(isGood(param, some_int_calculated_here)) doSmthElse();
}

现在您可以使用任何具有兼容签名的函数或函数对象(不一定需要以ParamTypeint作为参数)。否则,您将需要使用具有完全相同签名的函数。


如前所述,我想避免在函数头中使用函数符号来指定函数签名。 - Flamefire

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接