I'm trying to define a static variable of a templated class outside of the class scope using clang:
class Bar
{
public:
float a;
};
template<long count>
class Foo {
public:
static Bar* test;
};
template<long count>
decltype(Foo<count>::test) Foo<count>::test; // error
int main() {
Foo<5> f;
return 0;
}
But I get the following error:
error: redefinition of 'test' with a different type: 'decltype(Foo<count>::test)' vs 'Bar *'
It looks to me like decltype(Foo<count>::test) should evaluate to Bar *.
This code works fine on MSVC.
My question: Is there anyway to get decltype to correctly determine the type here?
In the actual code, decltype is defined in a macro that has some additional keywords depending on the configuration used, so I would like to get this working while still using decltype.
This code is ill-formed, because
decltype(Foo<count>::test)denotes a unique type, even though it is equivalent toBar*.The relevant standard sections are as follows:
- basic.scope.scope §4
We are even shown an example that declarations don't have to be symbolically identical to correspond:
- basic.scope.scope - example 2
However,
decltypeis special in this regard:- temp.type §4
In your example:
decltype(Foo<count>::test)is dependent oncount, and so the type is unique and different fromBar*. Proving that they are the same for arbitrary expressions is undecidable in the general case, so it makes sense that compilers disallow this.GCC falsely compiles your example (see Compiler Explorer), but clang and MSVC don't. This is probably because GCC doesn't treat
testas dependent, since it is declared with typeBar*, which is not dependent. However, that is not conforming.Conclusion
Your best course of action is finding a way to define this out-of-line with the same type:
If you can't use
Bar*directly, maybe there is another way for you to make your use ofdecltypenot depend oncount.Alternatively, you could also define the
staticmemberinline(since C++17):Note: I've personally run into a similar issue with the compiler being unable to match out-of-line definitions of member functions to the declarations in the class.