【问题标题】:How to pass a variable to a template metafunction?如何将变量传递给模板元函数?
【发布时间】:2021-06-13 02:15:31
【问题描述】:

我目前正在尝试学习如何使用模板元编程在 C++ 中编写功能代码

这是我对递归斐波那契序列生成器的尝试

template<int i, int x = 0, int y = 1>
struct Fib : Fib<i-1, y, x+y> {};

template<int x, int y>
struct Fib<0, x, y> {
    enum { value = x };
};

这似乎可以很好地获取值。 但是,当尝试将变量作为参数传递给 Fib&lt;i&gt;::value 之类的模板时,我得到编译器错误: the value of ‘i’ is not usable in a constant expression.

我的主要问题是如何避免或绕过这个错误? 但我也有关于如何使用这种代码将东西写入标准输出的问题,不知道我可以在哪里实现cout

【问题讨论】:

  • 好吧,你不能那样做。

标签: c++ templates


【解决方案1】:

没有办法“避免或绕过这个错误”。

这是 C++ 的基础:模板参数必须是编译时常量表达式。这意味着模板参数的值(或类型)必须在编译时完全定义。

普通变量是在运行时确定其值的东西。因此普通变量不能用作模板参数。

唯一的例外是称为constexpr 变量的特殊类型的变量,这些变量定义了在编译时完全确定的常量值。因此,constexpr 变量可以用作模板参数,因为它们满足编译时常量表达式的要求。

但是,如果您想生成由非constexpr 变量指定的斐波那契数列,您只需编写一个普通函数即可。

【讨论】:

  • 好的,谢谢,这是有道理的。但是我仍在努力了解我们将如何在任何有用的应用程序中实际使用这种编程?就像我将如何使用它来打印长度为 n 的斐波那契序列,例如不确定模板元函数是否实际上是无用的,或者我是否缺少一些我需要能够应用它们的东西?
  • 模板元编程以语言本身为目标。它并不打算用作函数式编程的替代品。例如,模板编程可用于生成查找表以高效解码 base64 编码的内容,但它不会用于实现实际解​​码本身,这是功能代码的职责。
【解决方案2】:

如何使用模板元编程在c++中编写函数式代码

您可能从错误的角度接近主题。元编程涉及编写有关如何编写程序的指令,达到超出正常编程的抽象级别。 (更多信息,我推荐 ShuggyCoUk 的A: What is metaprogramming?。)

当你编写一个类模板时,你并没有定义一个类。相反,您编写的指令告诉编译器如何编写适用于不同场景的类定义的变体。再读一遍那句话,但要认识到“计算机指令”意味着“程序”,而“类定义”是程序的一部分。那句话基本上是说写一个(类)模板就是写一个写程序(部分)的程序。编写程序的程序是“元编程”的“元”方面。

现在考虑一个典型 C++ 程序的生命周期。编写源代码,程序由编译器转换为可执行文件,然后运行可执行文件。编写、编译、然后运行,作为三个不相交的步骤。让我们假设向这个序列添加步骤不是一个选项。 (其他语言可能会选择不同的方法。)如果元编程产生的程序是可执行的,那么该程序最好在编译器完成之前就存在。

这是元编程的关键方面,因为它与这个问题有关。元程序与其他代码同时编写,生成的程序与正常运行时间相同。从“元程序”到“程序”的转换发生在编译期间。元程序由编译器“执行”以生成程序片段,然后将这些片段合并到您的代码的其余部分中。 元编程以编译器为目标。元程序的所有输入都必须是known by the compiler,因此在编译时就知道了。

编译器不知道大多数变量的值,因为值经常在程序运行时发生变化。这些值不能用作 C++ 元编程的输入。例外是标记为constexpr 的变量,该标记表示编译器可以知道该值。 constexpr 变量可以用作模板参数;其他变量不能。

具体情况:斐波那契

您的Fib 示例告诉编译器如何定义structs 系列的每个成员。对于ints 的任意三元组,编译器可以应用您的模板来生成相应struct 的定义。碰巧有一种方法可以从这个家族的某些成员那里获得某些斐波那契数,但在其核心,您只是编写了定义该家族成员的说明。

编译器不会创建该家族的所有可能成员。 (即使使用最小的int 实现,这个家族也有超过200 个trillion 成员。)相反,编译器只会创建它知道它需要的那些成员。您可以让编译器生成任何个特定的斐波那契数(达到一定的实现限制),但它不会生成每个斐波那契数(即使受限于该数小到可以放入int)。

元编程对于根据编译时已知的值进行计算很有用,但要根据运行时值进行计算,您需要一个运行时函数。 为工作使用正确的工具。

【讨论】:

    猜你喜欢
    • 2020-10-20
    • 2020-10-23
    • 1970-01-01
    • 2017-11-10
    • 2016-09-26
    • 1970-01-01
    • 1970-01-01
    • 2014-03-10
    • 2012-08-22
    相关资源
    最近更新 更多