I have a problem with this code snippet:
template <typename T>
struct S
{
static int a;
};
template <typename T>
decltype(S<T>::a) S<T>::a;
clang-3.4
says:
s.cpp:8:25: error: redefinition of 'a' with a different type: 'decltype(S<T>::a)' vs 'int'
decltype(S<T>::a) S<T>::a;
^
s.cpp:4:14: note: previous definition is here
static int a;
^
1 error generated.
But gcc-4.8.2
accepts. Which of the compilers is right? Should I avoid such code in the future?
Clang is demanding that the definition match the declaration at template definition time, whereas GCC and others defer matching until instantiation time (which never even happens for your example).
Clang accepts this:
#include <type_traits>
template <typename T>
struct S
{
static int a;
};
template <typename T>
typename std::enable_if< true, int >::type S<T>::a; // Resolves before instantiation
but rejects this small change:
template <typename T>
typename std::enable_if< std::is_same< T, T >::value, int >::type S<T>::a;
I cannot recall where the standard dictates when object declaration matching occurs, but I suspect that Clang is within its rights to reject the code. The intent of the standard, if I recall correctly, is that each declaration matches exactly one definition, and that mapping may be determined before instantiation time.
With the looser rule that GCC is apparently applying, you could have two member declarations and two definitions, but each definition may finalize either of the declarations depending on the template parameters.
The code which GCC and MSVC are accepting is ill-formed, no diagnosis required… pending finding the actual standardese buried somewhere in §3 [basic], §7 [dcl.dcl], §8 [dcl.decl], §14 [temp], or maybe somewhere else.
I still cannot find what rule matches object definitions to preceding declarations, but §14.4/2 dictates that decltype(…)
cannot be the equivalent (I assume in the declarative sense) to int
.
If an expression e involves a template parameter,
decltype(e)
denotes a unique dependent type. Two such decltype-specifiers refer to the same type only if their expressions are equivalent (14.5.6.1). [Note: however, it may be aliased, e.g., by a typedef-name. — end note ]
I'm pretty sure that equivalence, not mere aliasing, is necessary for the definition to match the declaration. §14.5.6.1 delves pretty deep into this territory, except it is specifically discussing function signatures.
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