Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

recursively nested templates -- gcc bug?

Tags:

c++

gcc

templates

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.

like image 884
xcvii Avatar asked May 01 '11 21:05

xcvii


2 Answers

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).

like image 166
Johannes Schaub - litb Avatar answered Oct 09 '22 10:10

Johannes Schaub - litb


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 {};
like image 31
iammilind Avatar answered Oct 09 '22 10:10

iammilind