I have the following snippet.
template< typename T >
struct f
{
template< typename V >
struct a : f
{};
};
int main ()
{
f<int>::a<int>::a<double> x;
}
It compiles with no warnings on GCC 4.4.5 and also MSVC 2010, but not on GCC 4.5.2 -- on which I get the following errors:
test.cc: In function 'int main()':
test.cc:11:21: error: expected primary-expression before 'double'
test.cc:11:21: error: expected ';' before 'double'
So while I don't see anything non-standard about it, the question is obligatory -- is this legal in C++? Also, if it is, how do I file a bug report at GCC? (:
edit: A little background for the curious:
This is supposed to be a piece of template metaprogramming. f
basically has the structure of a template metafunction class with apply
substituted for a
(of course the nested type
of apply
is omitted so we can concentrate on the structure itself).
Inheritance in this case is a standard device for binding metafunction return values. What this snippet is trying to achieve is a metafunction class that recursively yields itself when evaluated.
edit2: let me put the same snippet a bit differently:
template< typename T >
struct f
{
template< typename V > struct a;
};
template< typename T >
template< typename V >
struct f<T>::a : f<T>
{};
int main ()
{
f<int>::a<int>::a<double> x;
}
This produces the same error. I think it refutes the incomplete type argument.
There were a couple of good notes in existing answers. First, f
's type is incomplete at the time the nested class template is defined, but f
is a dependent type. Now, if you instantiate the nesting template (f
), it will instantiate a declaration of the nested template (the member). Note that the declaration of the member does not include the base clause list, so it doesn't need complete base classes. Once the nesting template has been instantiated implicitly, f
is complete and when it comes to instantiating the definition of the member, there should be no issue anymore. So I don't think that comeau is correct complaining here.
The other bug is that, in fact, f<int>::a<int>::a
is naming the constructor of a<int>
, and requires it to be a constructor template (with <int>
being the template arguments). The base of this was DR #147.
The translation to the constructor is not done when the qualifier name isn't the class of the injected class name. For example, if it is a derived class, your code becomes valid (as some answers figured out).
Nice question. This seems to be an issue with gcc
for template
recursive declaration. Because, had there been solid classes then it gives error and ideally it should be declared as:
struct Out {
struct In;
};
struct Out::In : Out {};
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