4

std::array<...>::size() is a non-static constexpr method; being constexpr I can use it as a template parameter:

#include <array>
#include <stdio>

int main(void) {
  std::array<char, 12> a = {{ "Hello world" }};
  std::cout << "size() = " << a.size() << ", data() = \"" << a.data() << "\"" << std::endl;

  std::array<char, a.size()> b = a;
  std::cout << "size() = " << b.size() << ", data() = \"" << b.data() << "\"" << std::endl;
}

However, if the std::array<...> is a template parameter, things become uncertain:

template <typename T>
void copy(T const& a) {
  std::array<char, a.size()> c = a;
  std::cout << "size() = " << c.size() << ", data() = \"" << c.data() << "\"" << std::endl;
}

GCC happily compiles this [1], while CLANG refuses [2] with

<source>:6:20: error: non-type template argument is not a constant expression
  std::array<char, a.size()> c = a;

[1] https://godbolt.org/z/Ru7Y3F
[2] https://godbolt.org/z/LYJcpo

Which one is correct, according to the standard ?


P.S. Yes, I know that I can work around it using std::tuple_size:

template <typename T>
void copy(T const& a) {
  std::array<char, std::tuple_size<T>::value> c = a;
  std::cout << "size() = " << c.size() << ", data() = \"" << c.data() << "\"" << std::endl;
}
Some programmer dude
  • 400,186
  • 35
  • 402
  • 621
fwyzard
  • 2,364
  • 1
  • 21
  • 19

1 Answers1

3

Clang is correct.

You are evaluating an id-expression (a) of reference type that does not has a preceding initialization, which is not allowed in a constant expression.

[expr.const]/2:

An expression e is a core constant expression unless the evaluation of e, following the rules of the abstract machine, would evaluate one of the following expressions:

  • ...

  • an id-expression that refers to a variable or data member of reference type unless the reference has a preceding initialization and either

    • it is initialized with a constant expression or

    • its lifetime began within the evaluation of e;

  • ...

xskxzr
  • 12,442
  • 12
  • 37
  • 77