C ++ 1y / C ++ 14:在常量表达式中不允许在其生命周期之外赋值给对象吗?

时间:2014-02-16 01:39:19

标签: c++ language-lawyer constexpr c++14

根据当前草案,以下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及其子对象的生命周期包含了函数,那么它的内容是什么?

1 个答案:

答案 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,回复中包含以下声明:

  

[...]问题是我们还没有实现隐含的规则,即不能在常量表达式中调用这样的函数。