【问题标题】:Template Metaprogramming: "does not have integral or enumeration type"模板元编程:“没有整数或枚举类型”
【发布时间】:2017-07-02 13:28:20
【问题描述】:

我正在尝试使用模板编写“强大”功能​​。

#define VAR_X 2.0f

template <int N> struct Power
{
    static const float ret = VAR_X * Power<N-1>::ret;
};

template <> struct Power<0>
{
    static const float ret = 1.0f;
};

我为变量使用了宏,因为浮点数不能用作模板参数。当我尝试用 g++ 5.4.0 编译时,我得到了这个:

tmptrig.cpp: In instantiation of ‘const float Power<1>::ret’:
tmptrig.cpp:35:28:   required from here
tmptrig.cpp:17:24: error: the value of ‘Power<0>::ret’ is not usable in a constant expression
     static const float ret = VAR_X * Power<N-1>::ret;
                        ^
tmptrig.cpp:22:24: note: ‘Power<0>::ret’ does not have integral or enumeration type
     static const float ret = 1.0f;

但是,当我将程序更改为仅处理整数时,它可以正常工作。

#define VAR_X 2

template <int N> struct Power
{
    static const int ret = VAR_X * Power<N-1>::ret;
};

template <> struct Power<0>
{
    static const int ret = 1;
};

我知道浮点数不能用作模板参数,但(据我所知)这里不是这样对待它们的。为什么我使用浮点数时编译器不喜欢它?

编辑:这就是我的main 的样子:

int main(int argc, char *argv[])
{
    std::cout << Power<1>::ret << std::endl;
}

【问题讨论】:

  • const 更改为constexpr
  • 这里使用宏完全没有帮助。宏只是在文本上被替换:它仍然是一个浮点数(因此是错误)。

标签: c++ templates floating-point template-meta-programming


【解决方案1】:

问题不在于浮点数不能是常量表达式,因为它们可以(尽管不允许作为模板非类型参数)。问题是您的代码需要明确标记它们,否则它们无法在类定义本身中初始化。

#include <iostream>

float constexpr var_x = 2.0f;

template <int N> struct Power
{
    static constexpr float ret = var_x * Power<N-1>::ret;
};

template <> struct Power<0>
{
    static constexpr float ret = 1.0f;
};

int main(int argc, char *argv[])
{
    std::cout << Power<1>::ret << std::endl;
}

这与您的原始意图几乎相同,因为 constexpr 意味着 const

Clang 对您的原始代码提供了更有用的警告:

error: in-class initializer for static data member of type 'const float' requires 'constexpr' specifier [-Wstatic-float-init]
    static const float ret = VAR_X * Power<N-1>::ret;

它们甚至可以在 C++03 中成为常量表达式(以及元函数的结果),但这需要类外定义:

float const var_x = 2.0f;

template <int N> struct Power
{
    static const float ret;
};

template <int N>
const float Power<N>::ret = var_x * Power<N-1>::ret;

template <> struct Power<0>
{
    static const float ret;
};

const float Power<0>::ret = 1.0f;

【讨论】:

  • 请从您的答案中删除那个无意义的宏。它让我哭泣。 :'-(
  • 我不认为 C++03 常量表达式可以包含浮点类型的变量。 (似乎即使在 C++11 及更高版本中,仍然不允许在常量表达式中使用非 constexpr 浮点变量。)
  • @KonradRudolph - 完成。必须承认我并没有真正注意到宏。我责怪隧道视野。
  • @cpplearner - 任何基本类型的常量变量在 C++ 中始终是常量表达式,只要它们的地址未被占用。它们必须是,否则任何用 const 替换宏的建议(在标题中,不少于)都不会站得住脚。
  • @cpplearner - 还有?一旦你施放它就不再是一个常量表达式了(你可以查一下)。或者声称这证明3.0f 也不是一个常量表达式?因为它是根据定义。
【解决方案2】:

int 版本之所以有效,是因为它会作弊。

来自[class.static.data]

如果一个非易失性非内联 const 静态数据成员是整数或枚举类型,它在类定义中的声明可以指定一个大括号或等式初始化器,其中每个初始化器-作为赋值表达式的子句是常量表达式

关于如何真正编写正确的代码,请查看StoryTeller's answer

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-02-13
    • 1970-01-01
    相关资源
    最近更新 更多