【问题标题】:Using a template callback function in C++在 C++ 中使用模板回调函数
【发布时间】:2013-08-23 19:21:54
【问题描述】:

我想要一个基于给定回调函数检查特定条件的函数。

考虑这段代码:

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“无法在 bool(ParamType,int) 中从 bool(int*,int) 转换参数 1”

我有一个不使用的解决方案

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

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

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

【问题讨论】:

  • 在回答之前我没有看到最后一行。为什么不能使用表示函子的模板参数?
  • 为我工作:ideone.com/czNr1e(在必要时添加/删除 typename 之后)。
  • @user2093113 checkEqualFloat 不会工作。
  • @mfontanini 确实,但那是因为问题中指定的checkEqualFloatIsGood&lt;float&gt;::Check 函数签名不匹配。更正签名以将int 作为第二个参数起作用:ideone.com/vx6ao8
  • @user2093113:您的代码正在运行。我只是忘记了一些事情:ParamTypes 是作为指针给出的。我更新了问题。对此感到抱歉。我想它必须是一样的。它可以工作但是在 IsGood 中省略指针并使用 "DoSmth(IsGood::Check" 但它看起来很奇怪

标签: c++ templates callback c2664


【解决方案1】:

问题是你的模板函数的第一个参数是不可推导的:

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&lt;ParamType&gt;::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)) { ...
}

【讨论】:

    【解决方案2】:

    使用仿函数模板将解决您的问题:

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

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

    【讨论】:

    • 如前所述,我想避免仿函数在函数头本身中指定函数签名
    猜你喜欢
    • 1970-01-01
    • 2011-10-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-02-16
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多