Cannot construct constexpr array from braced-init-list

[亡魂溺海] 提交于 2019-12-03 11:40:02

问题


I've implemented a constexpr array like this:

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);
}

Why is it that the first static_assert compiles, but initializing a fails?I'm using gcc 6.2.0. I'm getting

: 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);
   ^~~~~~~~~~~~~

回答1:


The compiler is complaining that the initializer of a.p is not a constant expression. It's failing §5.20/5.2:

if the value is of pointer type, it contains the address of an object with static storage duration, the address past the end of such an object (5.7), the address of a function, or a null pointer value

In other words, only pointer values known to the linker are valid constants. (Also, in your example the pointer is dangling.)

The first static_assert doesn't trip this because p is discarded and the value of n is a constant expression. Constant expressions may have non-constant subexpressions.

This works:

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

Credit to @Jarod42 for pointing out the issue in the comments.




回答2:


The problem was that you cannot imbue the constant nature of the pointer to T in the inner template through the outer template's T parameter.

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;
}

I tried a few dozen permutations to get rid of the cast without success.



来源:https://stackoverflow.com/questions/41420301/cannot-construct-constexpr-array-from-braced-init-list

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!