gpt4 book ai didi

c++ - 使用 std::initializer_list 的 constexpr 的奇怪行为

转载 作者:行者123 更新时间:2023-12-03 03:02:03 33 4
gpt4 key购买 nike

我试图理解为什么编译器在这里提示:

// cexpr_test.cpp
#include <initializer_list>

constexpr int test_cexpr(std::initializer_list<const char*> x)
{
return (int) (*x.begin())[0]; // ensuring the value isn't optimized out.
}

int main()
{
constexpr int r1 = test_cexpr({ "why does this work," });

constexpr std::initializer_list<const char*> broken { "but this doesn't?" };
constexpr int r2 = test_cexpr(broken);

return r1 + r2;
}

编译时产生的消息

g++ -std=c++11 -Wall -Werror cexpr_test.cpp 

如下:

cexpr_test.cpp: In function ‘int main()’: cexpr_test.cpp:12:76: error: ‘const std::initializer_list{((const char* const*)(&)), 1}’ is not a constant expression 12 | constexpr std::initializer_list broken { "but this doesn't?" }; |

令人困惑的是为什么它构建第一个初始化列表没有任何问题。我在这里缺少什么?

最佳答案

问题出在 broken 的初始化上本身在这里。什么是std::initializer_list它包含什么?它是一个引用类型(即以某种方式引用另一个对象),并且由 C 样式数组支持。此 C 风格数组的属性决定了initializer_list 是否可以是 constexpr 变量。我们可以查阅[dcl.init.list]来了解这些属性。

5 An object of type std​::​initializer_­list<E> is constructed from an initializer list as if the implementation generated and materialized a prvalue of type “array of N const E”, where N is the number of elements in the initializer list. Each element of that array is copy-initialized with the corresponding element of the initializer list, and the std​::​initializer_­list<E> object is constructed to refer to that array. [ Note: A constructor or conversion function selected for the copy shall be accessible in the context of the initializer list.  — end note ] If a narrowing conversion is required to initialize any of the elements, the program is ill-formed. [ Example:

struct X {
X(std::initializer_list<double> v);
};
X x{ 1,2,3 };

The initialization will be implemented in a way roughly equivalent to this:

const double __a[3] = {double{1}, double{2}, double{3}};
X x(std::initializer_list<double>(__a, __a+3));

assuming that the implementation can construct an initializer_­list object with a pair of pointers.  — end example ]

6 The array has the same lifetime as any other temporary object, except that initializing an initializer_­list object from the array extends the lifetime of the array exactly like binding a reference to a temporary. [ Example:

typedef std::complex<double> cmplx;
std::vector<cmplx> v1 = { 1, 2, 3 };

void f() {
std::vector<cmplx> v2{ 1, 2, 3 };
std::initializer_list<int> i3 = { 1, 2, 3 };
}

struct A {
std::initializer_list<int> i4;
A() : i4{ 1, 2, 3 } {} // ill-formed, would create a dangling reference
};

For v1 and v2, the initializer_­list object is a parameter in a function call, so the array created for { 1, 2, 3 } has full-expression lifetime. For i3, the initializer_­list object is a variable, so the array persists for the lifetime of the variable. For i4, the initializer_­list object is initialized in the constructor's ctor-initializer as if by binding a temporary array to a reference member, so the program is ill-formed ([class.base.init]).  — end example ] [ Note: The implementation is free to allocate the array in read-only memory if an explicit array with the same initializer could be so allocated.  — end note ]

所以这个数组就像任何其他由常量引用引用的临时对象一样。这意味着我们实际上可以将您的最小示例缩小到更小

constexpr int test_cexpr(int const & x)
{
return x;
}

int main()
{
constexpr int r1 = test_cexpr(0);

constexpr int const &broken = 0;
constexpr int r2 = test_cexpr(broken);

return r1 + r2;
}

这会产生 the exact same behavior and error 。我们可以通过0直接作为 constexpr 函数的参数,引用绑定(bind),我们甚至可以在函数内部引用它。但是,constexpr 引用可能无法用 0 进行初始化。零不是有效初始化器的原因是它需要具体化临时 int目的。该临时变量不是静态变量,因此不能用于初始化 constexpr 引用。就这么简单。

同样的推理也适用于您的情况。物化的临时数组不是具有静态存储持续时间的对象,因此它不能用于初始化 constexpr 引用类型。

直接将参数传递给test_cexpr时它起作用的原因,是相应的参数本身不是 constexpr 变量。这意味着它可以绑定(bind)成功。之后,它所绑定(bind)的东西必须可以在常量表达式中使用。无需对此进行太多详细说明:由于这种情况下的临时变量具有完整表达式的生存期(而不是扩展的生存期),因此它可以在常量表达式中使用。

关于c++ - 使用 std::initializer_list 的 constexpr 的奇怪行为,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59539488/

33 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com