Referring to a base class with template template parameters

View: New views
5 Messages — Rating Filter:   Alert me  

Referring to a base class with template template parameters

by Deth :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

I'm having issues referring to a base class under specific circumstances, and am hoping that someone can provide a work-around.

I have a base class A with a template template parameter T:

template <template <typename> class T>
class A {
public:
   A(int) {}
};

I then have a templated child class that derives from A using CRTP:

template <typename>
class B : public A {
public:
   B(int i)
      : A(i) {}
};

gcc reports the following error on the line with B's constructor initializer list:
"error: expected a class template, got 'B< <template-parameter-1-1> >

I can accomplish this in Visual Studio, but I can't find the syntax to make it work in gcc v4.2.1

It seems to be a specific issue with referring to A inside the definition of B.  Note that the following DOES compile

template <typename>
class Foo {
};

template <typename>
class B : public A<Foo> {
public:
   B(int i)
      : A<Foo>(i) {}

Is there some obscure syntax I can use to get around this?

Thanks for your help!
-Alex


Re: Referring to a base class with template template parameters

by Ian Lance Taylor-3 :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Deth <alexrepair@...> writes:

> I'm having issues referring to a base class under specific circumstances, and
> am hoping that someone can provide a work-around.
>
> I have a base class A with a template template parameter T:
>
> template <template <typename> class T>
> class A {
> public:
>    A(int) {}
> };
>
> I then have a templated child class that derives from A using CRTP:
>
> template <typename>
> class B : public A {
> public:
>    B(int i)
>       : A(i) {}
> };
>
> gcc reports the following error on the line with B's constructor initializer
> list:
> "error: expected a class template, got 'B< <template-parameter-1-1> >
>
> I can accomplish this in Visual Studio, but I can't find the syntax to make
> it work in gcc v4.2.1



I don't know why your code would work in Visual Studio.  To me it
looks wrong in several places.

This code works in gcc, and I believe is standard conformant.


template <typename T>
class A {
public:
   A(int) {}
};

template <typename T>
class B : public A<B<T> > {
public:
   B(int i)
     : A<B<T> >(i) {}
};


Ian

Re: Referring to a base class with template template parameters

by Deth :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

*EDIT* Bah - of course, <B> bolds text, so the code in my two posts didn't show up right.  Hopefully this works better:

Thanks Ian, but my code is definitely correct - lookup "template template" parameters if you're not familiar with the syntax in my post.

Your code is different because B<T> is a final type (not sure if that's the correct term).  In my example, class A can create a different template instantiation of B because B is declared as a 'template template' parameter.

This code without inheritance illustrates the problem a little clearer:

//template template syntax is required to allow A::makeAnIntC() to
//return a new template instantiation of C  
template <template <typename> class C>
class A {
        C<int> makeAnIntC() {return C<int>(5);}
};

template <typename T>
class Bee {
public:
        Bee(T) {}
        Bee<int> makeAnIntB() {return A<Bee>::makeAnIntC();} //Compile error here
};


Note that the following will compile and work:
class Foo {
   Bee<int> makeAnIntB() {return A<Bee>::makeAnIntC();} //Not self-referential
};


I found the following workarounds that at least get it to compile:

1.) Create a typedef outside of Bee:

   template <typename> class Bee; //forward declare Bee
   typedef A<Bee> AB;

   Bee can then call:
      return AB::makeAnIntC();

2.) This doesn't work if the type of A depends on a template parameter of Bee.  
     In that case, I found I could use an indirection class to declare the type:

   //Class A now depends on another type (specified by Bee)
   template <typename T, template <typename> class C>
   class A;

   template <typename> class B; //forward declare Bee
   template <typename T>
   class Typer {
      typedef A<T,Bee> Type;
   }

   Bee can then call:
   typedef typename Typer<T>::Type AB;
   return AB::makeAnIntC


Definitely not ideal, but it skirts around the problem for now.  This seems like a compiler bug to me - can anyone shed some insight?

Thanks,
-aG

Ian Lance Taylor-3 wrote:
I don't know why your code would work in Visual Studio.  To me it
looks wrong in several places.

This code works in gcc, and I believe is standard conformant.


template <typename T>
class A {
public:
   A(int) {}
};

template <typename T>
class B : public A<B<T> > {
public:
   B(int i)
     : A<B<T> >(i) {}
};


Ian

Re: Referring to a base class with template template parameters

by Ian Lance Taylor-3 :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Deth <alexrepair@...> writes:

> Thanks Ian, but my code is definitely correct - lookup "template template"
> parameters if you're not familiar with the syntax in my post.

You're right, I misunderstood what you wanted to do, but I'm not
convinced your code is correct according to the standard.  Your
original example said

template <typename>
class B : public A {

so it didn't provide any type for A's template parameter.  Shouldn't
it be

template <typename>
class B : public A<B> {

?  Otherwise, how does the compiler know what to use for A's template
parameter?

The problem then boils down to: how do you write the constructor

   B(int i)
     : A<...>(i) {}

The problem is that when you write

   B(int i)
     : A<B>(i) {}

B refers to the instantiated class B<>, not the template B.  So you
need to qualify it.  Is this code what you are after?

template <template <typename> class T>
class A {
public:
   A(int) {}
};

template <typename>
class B : public A<B> {
public:
   B(int i)
     : A< ::B>(i) {}
};

(note the space required between "<" and "::" to avoid a digraph).



> This code without inheritance illustrates the problem a little clearer:
>
> //template template syntax is required to allow A::makeAnIntC() to
> //return a new template instantiation of C  
> template <template <typename> class C>
> class A {
> C<int> makeAnIntC() {return C<int>(5);}
> };
>
> template <typename T>
> class B {
> public:
> B<int> makeAnIntB() {return A::makeAnIntC();} //Compile error here
> };

You're using A with no template parameter, and that is precisely what
the compiler complains about.


> Note that the following will compile and work:
> class Foo {
>    B<int> makeAnIntB() {return A::makeAnIntC();} //Not self-referential
> };

I see an error with this version as well.

foo.cc:15: error: ‘template<template<class> class C> class A’ used without template parameters


Ian

Re: Referring to a base class with template template parameters

by Deth :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Perfect!  That's exactly what I was looking for.  All of my "<B>" text was turned into HTML bold tags, so the code in my original post (and the pre-edit follow-up) was garbage.  Sorry for the confusion!

-Alex

Ian Lance Taylor-3 wrote:
B refers to the instantiated class B<>, not the template B.  So you
need to qualify it.  Is this code what you are after?

template <template <typename> class T>
class A {
public:
   A(int) {}
};

template <typename>
class B : public A<B> {
public:
   B(int i)
     : A< ::B>(i) {}
};

(note the space required between "<" and "::" to avoid a digraph).