When a class has a constexpr member function and that member function is being evaluated on an l-value object in a constexpr context, clang and gcc disagree whether the result is a constexpr value. Why? Is there a workaround that needs neither default-constructability nor copy-constructability?
When the object is passed by value, both compilers succeed compiling.
Clang versions trunk, 8, 7: static_assert expression is not an integral constant expression
and
Gcc versions trunk, 8.1, 7.4: compiles with no error
#include <array>
using A = std::array<int, 10>;
void foo(const A& a){
// clang: static_assert expression is not an integral constant expression
static_assert(a.size() > 0, "");
}
void foo2(A a){
// this compiles on both clang and gcc
static_assert(a.size() > 0, "");
}
// Some custom code with the same symptom:
class B{
public:
constexpr int size()const{
return 42;
}
};
void foo3(const B& b){
// clang: static_assert expression is not an integral constant expression
static_assert(b.size() > 0, "");
}
void foo4(B b){
// this compiles on both clang and gcc
static_assert(b.size() > 0, "");
}
https://godbolt.org/z/9vmyli
Workarounds with caveats:
void foo5(const B& b){
// This works in clang, if the default constructor is defined
static_assert(B().size() > 0, "");
}
void foo6(const B& b){
// This works in clang, if the copy constructor is defined
[](B b){static_assert(b.size() > 0, "");}(b);
}
As specified by the definition of core constant exprssions:
A core constant expression is any expression whose evaluation would not evaluate any one of the following:
...
- an id-expression referring to a variable or a data member of reference type, unless it was initialized with a constant expression or its lifetime began within the evaluation of this expression
...
So you are not allowed to have reference const A& a
here.
As an example, the following snippet compiles fine:
using A = std::array<int, 10>;
constexpr A arr = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
constexpr const A& arr_ref = arr; // OK: arr_ref is initialized with a constant expr
static_assert(arr.size() > 0, "");
static_assert(arr_ref.size() > 0, "");
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