根据当前草案,以下C ++ 14 / C ++ 1y程序是否格式不正确?
#include <cstddef>
template<typename T, size_t n>
struct literal_array
{
T data[n];
};
template<typename T, size_t n, size_t m>
constexpr literal_array<T, n+m> operator+(literal_array<T, n> a,
literal_array<T, m> b)
{
literal_array<T, n+m> x;
for (size_t i = 0; i < n; i++)
x.data[i] = a.data[i];
for (size_t i = 0; i < m; i++)
x.data[n+i] = b.data[i];
return x;
}
int main()
{
constexpr literal_array<int, 3> a = { 1, 2, 3 };
constexpr literal_array<int, 2> b = { 4, 5 };
constexpr auto c = a + b;
}
Clang trunk(在撰写本文时)给出:
error: constexpr variable 'c' must be initialized by a constant expression
constexpr auto c = a + b;
^ ~~~~~
assignment to object outside its lifetime is not allowed in a constant expression
x.data[i] = a.data[i];
^
in call to 'operator+({{1, 2, 3}}, {{4, 5}})'
constexpr auto c = a + b;
^
“在生命之外分配对象”是什么意思? x及其子对象的生命周期包含了函数,那么它的内容是什么?
答案 0 :(得分:10)
该程序格式错误,因为如果您将定义更改为:{/ p>,则不会初始化x
literal_array<T, n+m> x = {{0}};
clang
不再抱怨并且编译没有错误。另一种解决方案是创建 constexpr consrtuctors 。
我们可以在draft standard部分7.1.5
constexpr说明符段落 3 中找到:
constexpr
函数的定义应满足以下条件 约束:
并包含以下项目符号:
function-body 应为
= delete
,= default
或 复合语句,不包含
包含此子弹(强调我的):
非文字类型或静态或线程变量的定义 存储持续时间或未执行初始化。
以后我们有以下示例:
constexpr int uninit() {
int a; // error: variable is uninitialized
return a;
}
有关x
生命周期的投诉似乎并未在draft standard中找到。据我所知,正确的理由应该是object is not initialized
。
关于对象生命周期的标准草案的相关引用将是3.8
对象生存期段 1 的部分,其中包含:
对象的生存期是对象的运行时属性。一个 如果对象属于类,则称其具有非平凡的初始化 或者聚合类型,它或它的一个成员由a初始化 除了一个普通的默认构造函数之外的构造函数。 [注意: 通过简单的复制/移动构造函数进行初始化是非常重要的 初始化。 - 结束注释]类型为
T
的对象的生命周期开始 当:
- 获得具有
T
类型的正确对齐和大小的存储,并且- 如果对象具有非平凡的初始化,则其初始化完成。
万一我错过了一些我还使用std::is_trivial检查的内容:
std::cout << std::boolalpha << std::is_trivial<literal_array<int, 3>>::value << std::endl ;
以及true
,。
更新
我为此提交了bug report,回复中包含以下声明:
[...]问题是我们还没有实现隐含的规则,即不能在常量表达式中调用这样的函数。