根据当前草案,以下 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 及其子对象的生命周期包含该函数,那么它是关于什么的?
该程序是格式错误,因为您没有初始化
x
,如果您将定义更改为:
literal_array<T, n+m> x = {{0}};
clang
不再抱怨并且编译没有错误。另一个解决方案是创建 constexpr 构造函数。
我们可以在标准草案部分
7.1.5
constexpr说明符段落3中找到它,其中写着:
函数的定义应满足以下条件 限制条件:constexpr
并包括以下项目符号:
其功能体应为
、= delete
或 复合语句不包含= default
其中包含这个项目符号(强调我的):
非文字类型或静态或线程变量的定义 存储持续时间或者没有执行初始化。
稍后我们有以下示例:
constexpr int uninit() {
int a; // error: variable is uninitialized
return a;
}
对于
x
的生命周期的抱怨似乎在标准草案中没有成立。据我所知,正确的原因应该是object is not initialized
。
对象生命周期标准草案的相关引用将是第
3.8
对象生命周期第 1 节,其中表示:
对象的以防万一我遗漏了一些东西,我还使用lifetime 是对象的运行时属性。一个 如果对象属于类,则称该对象具有重要的初始化 或聚合类型,并且它或其成员之一由 除了简单的默认构造函数之外的构造函数。 [ 注: 通过简单的复制/移动构造函数进行初始化并不简单 初始化。 — 尾注 ] 类型为
T
的对象的生命周期开始 什么时候:获得具有适合类型
- 如果对象进行了重要的初始化,则其初始化已完成。
T
的正确对齐和尺寸的存储,并且
std::is_trivial: 检查过
std::cout << std::boolalpha << std::is_trivial<literal_array<int, 3>>::value << std::endl ;
结果如预期 true
,.
更新
我为此提交了一份错误报告,回复包括以下声明:
[...]问题是我们还没有实现这样的函数不能在常量表达式中调用的隐含规则。