Minimal example:
#include <cstddef>
struct B
{
constexpr static const size_t MAX = 10;
};
struct D : B
{
constexpr static const size_t MAX = 20;
};
void use(const B& v)
{
static_assert(v.MAX == 10, "");
}
template<typename X>
void use2(X&& v)
{
static_assert(v.template MAX == 20, "");
}
int main ()
{
D d;
static_assert(d.MAX == 20, "");
use(d);
use2(d);
return 0;
}
GCC (v5.4 ... v7.3): compiles fine (any level of optimization and -Wall -Wextra -pedantic) ICC / MSVC : compiles fine (tried with various versions on godbolt.org)
CLANG (v4 ... v6) : error: static_assert expression is not an integral constant expression static_assert(v.MAX == 10, "");
EDIT (rephrasing the question) :
In my opinion clang's behaviour is the least surprising one (or the more intuitive). Given it's the only compiler failing to compile the above code, I'd like to understand which of the 2 behaviours is correct and why?
EDIT 2 :
Judging by this addition of a template function, gcc looks to use the declared type of the parameter and work out which constexpr member to use regardless of what's passed in.
If passing by value, clang will also assess MAX as a constant expression. In this case it is obvious why v.MAX == 10 would be true for all compilers for non-templated function.
EDIT 3 (even shorter version): Which still does not compile on clang
#include <cstddef>
struct B
{
constexpr static const size_t MAX = 10;
};
void use(const B& v)
{
static_assert(v.MAX == 10, "");
}
template<typename X>
void use2(X&& v)
{
static_assert(v.template MAX == 10, "");
}
int main ()
{
B v;
static_assert(v.MAX == 10, "");
use(v);
use2(v);
return 0;
}
Clang is correct.
v.MAX == 10
evaluates v
, which is a reference without a preceding initialization. This is not allowed in a constant expression.
Note even if MAX
is a static member, v
is still evaluated during the evaluation of v.MAX
.
You can use the class type to access MAX
to avoid the evaluation of v
, for example
void use(const B& v)
{
static_assert(B::MAX == 10, "");
// ^^^
}
template<typename X>
void use2(X&& v)
{
static_assert(std::remove_reference_t<X>::MAX == 10, "");
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
}
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