【问题标题】:Literal value is not being considered a constant expression during template instantiation在模板实例化期间,字面值不被视为常量表达式
【发布时间】:2018-03-19 08:19:45
【问题描述】:

这段代码应该在编译时使用模板元编程检查浮点数是否等于整数的一半: #包括

struct A {
    constexpr static bool value = true;
};

struct B {
    constexpr static bool value = false;
};

template<int i>
struct Meta {
    constexpr static int value = i/2;
    constexpr static bool func(float n) {
        return std::conditional_t<n==value,A,B>::value;
    }
};


int main( int argc, const char *argv[] ) {
    constexpr bool b = Meta<4>::func(2);
    std::cout << b << std::endl;
    return 0;
}

但它拒绝编译。编译器说n is not a constant expression:

test.cpp: In substitution of ‘template<bool _Cond, class _Iftrue, class _Iffalse> using conditional_t = typename std::conditional::type [with bool _Cond = (n == (float)2); _Iftrue = A; _Iffalse = B]’:
test.cpp:15:50:   required from ‘static constexpr int Meta<i>::func(float) [with int i = 4]’
test.cpp:21:36:   required from here
test.cpp:15:50: error: ‘n’ is not a constant expression
         return std::conditional_t<n==value,A,B>::value;
                                                  ^~~~~
test.cpp:15:50: note: in template argument for type ‘bool’ 
test.cpp: In function ‘int main(int, const char**)’:
test.cpp:21:36:   in constexpr expansion of ‘Meta<4>::func((float)2)’
test.cpp:21:38: error: constexpr call flows off the end of the function
     constexpr int b = Meta<4>::func(2);
                                      ^

这里有什么问题?传递给Meta::func 的值是文字值。它应该被视为一个常量。

我感兴趣的是如何在编译时根据值执行不同的操作。这应该是可能的,因为计算输出所需的所有输入都在编译时可用。

我想知道如何在编译时根据值执行不同的操作(可能涉及类型)。这应该是可能的,因为计算输出所需的所有输入都在编译时可用。

【问题讨论】:

  • constexpr 函数仍然是一个常规函数,可以在运行时使用任意 n 调用。那么if constexpr 将如何处理呢?
  • 在调用函数时使用了字面量整数值,但在函数内部它不再是字面量而是普通变量。 “传递”文字值的唯一方法是将func 设为非类型模板,并将n 作为模板参数。这不适用于浮点类型。
  • @StoryTeller 如帖子所述,我希望在编译时计算该值。我正在尝试了解模板实例化如何与此代码一起使用。
  • 在不相关的说明中,您知道浮点比较的相等性几乎没有用吗?
  • @saga 浮点计算总是存在可能发生舍入的问题。进行两次不同的计算(有时甚至使用不同的值进行相同的计算)在数学上应该会产生相同的结果,但由于四舍五入的影响,可能会得到两个不完全相同的值。这就是为什么您不应该比较浮点值是否完全相等,而是因为它们的差异足够小......

标签: c++ templates metaprogramming template-meta-programming


【解决方案1】:

问题是生成的一个函数需要使用常量表达式(如您的文字)以及可变修改的值(例如以前计算的结果)都可以调用.

函数的constexpr属性保证函数在编译时被求值,if有可能是因为all参数是常量表达式。如果其中任何一个不是,则该函数用作在运行时评估的 普通 函数。即使您从未以这种方式使用该函数,它仍然必须能够处理这种情况,因此一般的函数参数(n)永远不能用作constexpr,因此n == value也不能;不管是在if constexpr 中使用还是(在您编辑之后)作为模板参数使用。

然而,实际上,内部 if constexpr 无论如何都已过时:您使用编译时常量提供 constexpr 函数,因此上述保证适用,并且您的函数 在编译时进行评估,无论如何如果您使用if constexpr,那么您的功能可以简化为:

constexpr static bool func(float n)
{
    return n == value;
}

请注意,如果这没有按预期出现,您也无法将结果分配给 constexpr bool...

已在问题的 cmets 中表示,但重要到足以再次提示:也要注意浮点算术的舍入问题以及通过精确相等性比较此类值!

【讨论】:

  • Actually, however, the inner if constexpr is obsolete anyway 我提供的示例非常简单。它不应该有任何实际用途。我感兴趣的是如何根据值at compile time 执行不同的操作。这应该是可能的,因为计算输出所需的所有输入在编译时都可用。
  • 我的回答中的陈述不会改变,无论函数多么复杂,如果提供的所有参数都是编译时常量,则函数 被评估为编译时间...
  • 值'2',作为参数传递给Meta::func是一个编译时间常数。
  • @saga Yes 是,因此函数的结果在编译时可用。但是即使你不这样做,函数也可以被调用,并得到 e 的结果。 G。 rand()(已弃用!),因此不能将函数参数视为编译时常量。
  • Yes it is, thus the function's result will be available at compile time 不,结果在编译时不可用。此代码无法编译。你想说什么?
猜你喜欢
  • 2018-06-01
  • 2019-06-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多