[英]Why is calling a constexpr function with a member array not a constant expression?
I have the following helper function: 我有以下帮助函数:
template<typename T, std::size_t N>
constexpr std::size_t Length(const T(&)[N]) {
return N;
}
Which returns the length of a static array. 返回静态数组的长度。 In the past this always has worked but when I do this:
在过去,这总是有效,但当我这样做时:
struct Foo
{
unsigned int temp1[3];
void Bar()
{
constexpr std::size_t t = Length(temp1); // Error here
}
};
I get an error when using MSVS 2017: 使用MSVS 2017时出错:
error C2131: expression did not evaluate to a constant note: failure was caused by a read of a variable outside its lifetime note: see usage of 'this'
I was hoping someone can shed light on what I'm doing wrong. 我希望有人能说清楚我做错了什么。
MSVC is correct. MSVC是正确的。
Length(temp1)
is not a constant expression. Length(temp1)
不是常量表达式。 From [expr.const]p2 来自[expr.const] p2
An expression e is a core constant expression unless the evaluation of e , following the rules of the abstract machine, would evaluate one of the following expressions:
表达式e是核心常量表达式,除非根据抽象机器的规则评估e将评估以下表达式之一:
this
, except in a constexpr function or a constexpr constructor that is being evaluated as part of e ;this
,除了在constexpr函数或constexpr构造函数中被评估为e的一部分;
temp1
evaluates this
implicitly (because you are referring to this->temp1
), and so you don't have a constant expression. temp1
隐式计算this
(因为你指的是this->temp1
),所以你没有常量表达式。 gcc and clang accept it because they support VLAs as an extension (try compiling with -Werror=vla
or -pedantic-errors
). gcc和clang接受它,因为它们支持VLA作为扩展(尝试使用
-Werror=vla
或-pedantic-errors
编译)。
Why isn't this allowed? 为什么不允许这样做? Well, you could access the underlying elements and potentially modify them.
好吧,您可以访问底层元素并可能修改它们。 This is completely fine if you are dealing with a
constexpr
array or an array that is being evaluated as a constant expression, but if you are not, then you cannot possibly have a constant expression as you will be manipulating values that are set at run time. 如果你正在处理一个
constexpr
数组或一个被评估为常量表达式的数组,这是完全正常的,但如果不是,那么你不可能有一个常量表达式,因为你将操纵在运行时设置的值。
Length(decltype(temp1){})
seems to work . 似乎工作 。
Unfortunately, I cannot comment, but Mehrdad 's solution is wrong. 不幸的是,我无法评论,但Mehrdad的解决方案是错误的。 The reason: it is not technically undefined behavior but it is undefined behavior.
原因是:它不是技术上未定义的行为, 但它是未定义的行为。 During constexpr evaluation, the compiler must catch undefined behavior.
在constexpr评估期间,编译器必须捕获未定义的行为。 Therefore, the code is ill-formed .
因此, 代码是不正确的 。
Your question's already been answered, but in terms of how to "fix" it, a quick-and-dirty way is to replace 你的问题已经得到了回答,但就如何“修复”而言,一种快速而又肮脏的方式就是取而代之
Length(temp1)
with 同
Length(*(true ? NULL : &temp1))
which I think is technically undefined behavior but practically going to work fine for MSVC. 我认为这是技术上未定义的行为,但实际上对MSVC来说工作正常。
If you need a solution that works despite the UB, you can change Length
to use a pointer: 如果您需要一个尽管有UB的解决方案,您可以更改
Length
以使用指针:
template<typename T, std::size_t N>
constexpr std::size_t Length(const T(*)[N]) {
return N;
}
and then you can use Length(true ? NULL : &temp1)
. 然后你可以使用
Length(true ? NULL : &temp1)
。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.