What should happen if an expression's type is not dependent, but we use it to initialize a static auto variable? GCC and Clang differ in their behavior
template<typename T>
struct A {
static inline auto x = sizeof(T{}.f);
};
A<int> a;
GCC doesn't raise an error. But Clang thinks that this is invalid because it instantiates the operand of "sizeof". GCC appears to skip that step because sizeof(T{}.f)
always has type size_t
(not type dependent), so it already knows type of x
without instantiation. Both compilers conformly reject the program if we refer to x
, for example by (void) a.x;
.
Does it even have to resolve the type of x
at all? With C++14 upwards the language allows keeping things (like functions) with a "placeholder type" and doing delayed instantiation to find out about the actual return type later on, if I remember correctly. Does it have to apply this to x
aswell, so keeping x
with a placeholder type till we refer to a.x
?
What compiler is correct according to the Standards?
EDIT
Someone asked
uhm, shouldnt' this be equivalent to this ?
template<typename T> struct A { static const std::size_t x; }; template<typename T> inline constexpr std::size_t A<T>::x = sizeof(T{}.f);
The difference, and what concerns me in my question, is that the static data member in my question is auto
. Therefore, in order to know the type of x
, you need to know the type of the initializer. Clang appears to instantiate the initializer eagerly in order to get the type. But GCC doesn't, apparently? I would like to understand what's going on.
From [temp.inst]/3:
Unless a member of a class template or a member template has been explicitly instantiated or explicitly specialized, the specialization of the member is implicitly instantiated when the specialization is referenced in a context that requires the member definition to exist; in particular, the initialization (and any associated side effects) of a static data member does not occur unless the static data member is itself used in a way that requires the definition of the static data member to exist.
Simply writing A<int> a;
does noes not use A<int>::x
in a way that requires its definition to exist, so its initialization should not occur. gcc is correct.
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