Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

static member of class template error

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?

like image 901
user1095108 Avatar asked Apr 24 '14 08:04

user1095108


Video Answer


1 Answers

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.

like image 96
Potatoswatter Avatar answered Oct 14 '22 11:10

Potatoswatter