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);
^~~~~~~~~~~~~
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With