[英]constexpr initializer_list raising an error: "expression must have a constant value -- reference or pointer to temporary with limited lifetime"
Here's the problem:这是问题所在:
int main()
{
constexpr std::initializer_list<int> my_ints {1, 2, 3};
}
I'm trying to compile the above with g++ (x86_64-posix-seh-rev0, version 8.1.0).我正在尝试使用 g++ (x86_64-posix-seh-rev0, version 8.1.0) 编译上述内容。 But VS Code raises the following warning:
但是 VS Code 引发了以下警告:
"expression must have a constant value -- reference or pointer to temporary with limited lifetime" “表达式必须有一个常量值——生命周期有限的临时引用或指针”
When I remove the constexpr
specifier, that is, when I amend the code to当我删除
constexpr
说明符时,也就是当我将代码修改为
int main()
{
std::initializer_list<int> my_ints {1, 2, 3};
}
the error goes away, so it seems there's something wrong with declaring a constexpr initializer_list
.错误消失了,因此声明
constexpr initializer_list
似乎有问题。
Yet according to this reference ( https://en.cppreference.com/w/cpp/utility/initializer_list/initializer_list ), it should be perfectly fine to declare a constexpr initializer_list
.然而,根据这个参考( https://en.cppreference.com/w/cpp/utility/initializer_list/initializer_list ),声明一个
constexpr initializer_list
应该是完全没问题的。
Can someone with deeper insight into the workings of constexpr
and initializer_list
explain why this is happening?对
constexpr
和initializer_list
的工作有更深入了解的人可以解释为什么会发生这种情况吗?
There's a clue to the cause of this problem over at cppreference :在cppreference有一个关于这个问题原因的线索:
An object of type std::initializer_list is a lightweight proxy object that provides access to an array of objects of type const T.
std::initializer_list 类型的对象是一个轻量级代理对象,它提供对 const T 类型的对象数组的访问。
and:和:
Initializer lists may be implemented as a pair of pointers or pointer and length.
初始化列表可以实现为一对指针或指针和长度。
In other words, when you do this at local scope:换句话说,当您在本地范围内执行此操作时:
std::initializer_list<int> my_ints {1, 2, 3};
the compiler has to allocate (and initialise) {1, 2, 3}
on the stack, so it can't be constexpr
.编译器必须在堆栈上分配(并初始化)
{1, 2, 3}
,因此它不能是constexpr
。
Fortunately, there's an easy workaround.幸运的是,有一个简单的解决方法。 Just do:
做就是了:
static constexpr std::initializer_list<int> my_ints {1, 2, 3};
Now the underlying array is allocated at compile time and therefore can be constexpr
.现在底层数组在编译时分配,因此可以是
constexpr
。
The difference in the code generated can be seen at Godbolt .生成的代码的差异可以在Godbolt看到。
Edit: OP asks (in effect) can a stack-based variable ever be constexpr
?编辑: OP 询问(实际上)基于堆栈的变量可以是
constexpr
吗? Well, the answer is yes, if all the members of that object can be evaluated at compile time.好吧,答案是肯定的,如果该对象的所有成员都可以在编译时进行评估。
So, to go back to the original example, when you write:所以,回到原来的例子,当你写:
std::initializer_list<int> my_ints {1, 2, 3};
a std::initializer_list
generally consists of a pointer to the underlying array and a length, so, here, the compiler has to push 1
, 2
and 3
onto the stack at runtime, and then put a pointer and a length to that "array" into my_ints
, so my_ints
cannot be constexpr
since the address of said array is not known at compile time. std::initializer_list
通常由指向底层数组的指针和长度组成,因此,在这里,编译器必须在运行时将1
、 2
和3
压入堆栈,然后将指针和长度放入该“数组” " 进入my_ints
,所以my_ints
不能是constexpr
因为在编译时不知道所述数组的地址。
OTOH, something like: OTOH,类似于:
constexpr int i = 42;
is fine, since 42 is (obviously) known at compile time and that's all the compiler cares about.很好,因为 42 在编译时(显然)是已知的,这就是编译器关心的全部。
Interestingly:有趣的是:
constexpr char s [] = "abcde";
also works.也有效。 If you look at the code generated , the compiler allocates "abcde" in static storage and then copies this to
s
at runtime.如果查看生成的代码,编译器会在静态存储中分配“abcde”,然后在运行时将其复制到
s
。 Why it doesn't do something similar in the case of std::initializer_list
is a bit of a mystery (to me, at least).为什么它在
std::initializer_list
的情况下不做类似的事情有点神秘(至少对我来说)。
And finally, why does declaring my_ints
static
fix things?最后,为什么声明
my_ints
static
? Well, now the compiler can allocate and initialise 1,2,3
at compile time and this "array" now is at an address which is known at compile time so my_ints
can be constexpr
.那么,现在的编译器可以分配并初始化
1,2,3
在编译时,该“阵列”现在处于其在编译时已知的,因此地址my_ints
可以constexpr
。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.