无法从braced-init-list构造constexpr数组

时间:2017-01-02 00:43:16

标签: c++ arrays constructor c++14 constexpr

我已经实现了这样的constexpr数组:

template <typename T>
class const_array {
  const T* p;
  unsigned n;
public:
  template <unsigned N>
  constexpr const_array(const T(&a)[N]): p(a), n(N) { }

  constexpr unsigned size() const { return n; }
};

int main(int argc, char* argv[]) {
  // works
  static_assert(const_array<double>{{1.,2.,3.}}.size() == 3);

  // doesn't compile
  constexpr const_array<double> a{{1.,2.,3.}};
  static_assert(a.size() == 3);
}

为什么第一个static_assert编译,但初始化a失败?我使用的是gcc 6.2.0。我得到了

: In function 'int main(int, char**)':
: error: 'const_array<double>{((const double*)(&<anonymous>)), 3u}' is not a constant expression
   constexpr const_array<double> a{{1.,2.,3.}};
                                        ^
test/const_array.cc:17:3: error: non-constant condition for static assertion
   static_assert(a.size() == 3);
   ^~~~~~~~~~~~~

2 个答案:

答案 0 :(得分:11)

编译器抱怨a.p的初始值设定项不是常量表达式。它失败了§5.20/ 5.2:

  

如果值是指针类型,则它包含具有静态存储持续时间的对象的地址,超过此类对象结尾的地址(5.7),函数的地址或空指针值

换句话说,只有链接器已知的指针值才是有效常量。 (另外,在你的例子中,指针悬空。)

第一个static_assert不会使其失效,因为p被丢弃,n的值是常量表达式。常量表达式可能具有非常量子表达式。

这有效:

static constexpr double arr[] = { 1.,2.,3. };
constexpr const_array<double> a{ arr };
static_assert( a.size() == 3 );

感谢@ Jarod42在评论中指出了这个问题。

答案 1 :(得分:-1)

问题是你不能通过外部模板的T参数来灌输内部模板中指针T的恒定性质。

template <typename T> class const_array {
    const T * p;
    unsigned n;
public:
    template <unsigned N>
        constexpr const_array(const T(& a)[N]): p(a), n(N) { }
};

int main(int argc, char* argv[]) {
    constexpr const_array<double> ca{(const double []) { 1., 2. }};
    return 0;
}

我尝试了几十种排列以摆脱演员而没有成功。