- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我试图理解为什么编译器在这里提示:
// 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 ofN
const E
”, whereN
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 thestd::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
andv2
, theinitializer_list
object is a parameter in a function call, so the array created for{ 1, 2, 3 }
has full-expression lifetime. Fori3
, theinitializer_list
object is a variable, so the array persists for the lifetime of the variable. Fori4
, theinitializer_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/
我需要使用 initializer_list 来初始化编译时大小的类数组。我已经知道我可以使用参数包构造函数并当场初始化它,但在这种情况下我需要使用 initializer_list。如果可能,我还想
我有一个类构造函数接受一个 initializer_list 这个构造函数必须运行接受一个的父类构造函数 initializer_list>. 所以我必须将初始化列表转换为二维初始化列表。 {1, 2
这个问题在这里已经有了答案: 关闭10 年前。 Possible Duplicate: initializer_list and move semantics 环境:Linux,g++-4.7 我使
以下代码编译并运行: #include #include #include #include void ext( std::initializer_list >> myList ) {
std::vector的初始化列表构造函数具有以下形式 vector( std::initializer_list init, const Allocator& alloc = Allocator()
考虑以下代码片段... void boo(std::initializer_list l) { } template void foo(std::initializer_list l) {
我的问题是关于 std::initializer_list 之间缺乏转换当这些转换看起来很容易实现时,包含的类型或多或少是 cv 限定的类型。 考虑以下无效代码: std::initializer_l
我的图表构造函数: Graph(std::initializer_list list); 我的边缘构造函数: Edge(int out, int in); 我想通过以下方式创建我的图表: Graph
我有一些我想在编译时由需要某种程度验证的初始化列表初始化的类。 我首先尝试使用static_assert,但不会与错误“静态声明的非恒定条件”一起编译 造成此错误的最佳方法是什么? class foo
//parameter pack sum example constexpr int sum(int N= 0) { return N; } template constexpr int su
我是新来的,这是我的第一个问题。 所以,我有这个功能: std::string join(string_initializer_list p_input) const { std::strin
想问一下有没有机会补上引用功能。假设我有功能: double refce( double (&f1)(double), double in ){ return f1(in); } 而不是这样调
所以我昨天尝试开始使用 std::initializer_list 但这并不是一个巨大的成功。这是我最后的尝试之一: #include #include struct XmlState
考虑函数: template void printme(T&& t) { for (auto i : t) std::cout ({'a', 'b', 'c'})); printme(st
考虑函数: template void printme(T&& t) { for (auto i : t) std::cout ({'a', 'b', 'c'})); printme(st
我想用 std::initializer_list 初始化基类。 struct A : public std::array { // This constructor works fine A
基于这段代码 struct Foo { Foo() { cout ilist) { cout 构造函数的大括号初始化中。 相反,复制构造函数带头。 你
尝试为 Node 安装 phash-image 但出现此错误: > phash-image@3.1.0 install /Users/jong/Workspace/mgmtio/phash-image
下面对 foo 的调用是否有效? GCC 似乎对此很满意,而 Clang 为 foo 给出了“无匹配函数”错误;以及无法推断出 N 的注释。 template void foo(const int
我正在尝试使用函数模板 foo 将参数转换为 initializer_list。但是,它转换的 initializer_list 具有与输入参数不同的奇怪值。 #include #include
我是一名优秀的程序员,十分优秀!