【问题标题】:C++ Templates: Function as Template Class ParameterC++ 模板:作为模板类参数的函数
【发布时间】:2014-01-15 10:21:49
【问题描述】:

所以在 C++ 中,我们可以像这样将函数作为模板参数传递:

template <typename func>
int tester(func f)
{
    return f(10);
}

所以我有一个使用函数的模板类,我一直在这样使用它,每次我都会将函数和变量传递给它。

template <typename type_t>
class TCl
{
    ...
    template <typename func>
    int Test(func f, type_t Var>
    {
         // Blah blah blah
    }
};

但我想让函数成为类模板参数之一,以使其更易于使用。 所以我首先尝试了这个:

template <typename func>
template <typename type_t, func f>
class TCl
{
    ...
};

但是当我编译这个时,我得到:

编译器错误 C3857:不允许使用多个类型参数列表

因为上帝禁止我的代码在我第一次尝试时实际上应该编译。

现在我的问题是,虽然我知道函数的参数类型(在本例中为 size_t、size_t),但返回类型可以是任何类型,只要 type_t 有适当的比较运算符。

经过几个小时的在线阅读,我找到了一个可行的解决方案。

template <typename type_t, typename ret_t, ret_t f(size_t, size_t)>
class TCl
{
    ...
};

虽然它有效,但它有点破坏代码的美感。而且我更喜欢在原始示例中指定 func 类型的东西,而不必担心指定返回类型。

那么有人有什么建议吗?

此外,没有 Boost。

编辑: 解决了!

谢谢你们。我使用了 Jarod42 的解决方案。

@Drax & Lightness Races in Orbit:

我曾考虑过将类型放在手头,但它会给程序员带来负担来定义函数指针以便使用它,这似乎是不必要的残忍:)

然而,Jarod42 使用宏和 decltype 运算符解决了这个问题,我完全忘记了。

您的示例 Jarod42 有一个小问题。

#define TCl_T(type_t, function) Tcl<type_t, decltype(function), function>

产生错误: 错误 C1001:编译器发生内部错误。

这样就解决了。

#define TCl_T(type_t, function) Tcl<type_t, decltype(&function), function>

显然我们必须指定它是一个指针。

再次感谢大家的帮助!

【问题讨论】:

  • template &lt;typename type_t, typename func&gt; 有什么问题?编辑:哦,你不想将函数作为参数传递给Test
  • 它们被称为“类/函数模板”,而不是“模板类/函数”
  • 这看起来很像我遇到的问题here。在我看来,在处理类模板时需要模板非类型参数推导。尽管宏是邪恶的,应该避免,但 Jarod42 的以下答案是您需要美学时的唯一解决方案。
  • we can pass functions as template parameters 虽然这是真的(通过函数指针),但您只是将函数 type 作为模板参数传递,函数指针本身作为普通函数争论。不过,我认为您意识到了这一点,因为您的目标是开始将函数指针本身作为模板参数传递。

标签: c++ function templates parameters metaprogramming


【解决方案1】:

与:

template <typename type_t, typename ret_t, ret_t f(size_t, size_t)>
class TCl;

您可以使用宏:

#define TCl_T(type_t, function) Tcl<type_t, decltype(function(0, 0)), function>

然后像这样使用它:

// bool my_func(size_t, size_t);
TCl_T(int, my_func) tcl; // tcl is a Tcl<int, bool, my_func>

如果您将 TCl 更改为:

template <typename type_t, typename prototype_t, prototype_t f>
class TCl;

您可以使用宏:

#define TCl_T(type_t, function) Tcl<type_t, decltype(function), function>

【讨论】:

    【解决方案2】:

    好吧,只需将模板参数放在同一行:

    template <typename type_t, typename func, func f>
    class TCl
    {
        ...
    };
    

    【讨论】:

      【解决方案3】:

      而且我更喜欢在原始示例中指定 func 类型的东西,而不必担心指定返回类型。

      好的,那么就这样做吧! :-) 我不明白您为什么从将整个函数类型作为模板参数传递,到将其拆分为返回类型和参数类型。而且,在这样做的过程中,您介绍了您陈述的问题。但是您没有解释为什么要进行此更改。

      为什么不简单:

      template <typename type_t, typename func_t, func_t f>
      class TCl
      {
          // ...
      };
      

      这是您自己的方法的逻辑演变,不是吗?

      这是一个有效的例子:

      #include <iostream>
      
      template <typename type_t, typename func_t, func_t f>
      struct T
      {
          T() { f(); }
      
          type_t a;   /**< Irrelevant here, but gives your `type_t` something to do */
      };
      
      void foo() { std::cout << "A\n"; }
      int  bar() { std::cout << "B\n"; return 0; }
      
      int main()
      {
          T<int, void(*)(), &foo> t1;
          T<int, int (*)(), &bar> t2;
      }
      
      // Output:
      //  A
      //  B
      

      Live demo

      可惜你不能在 template-argument-list 中使用更多的推论。 Jarod42 有一个有趣的想法,使用宏来缩短调用时间,但我不确定它是否能改善美感。

      我想知道这是否意味着你的断言:

      使函数成为类模板参数之一,使其更易于使用

      是假的。

      【讨论】:

        最近更新 更多