template template specialization

  • Follow


Hello,

I get an error on Visual Studio 7.1 when I try to compile the
following code:

1 template <class T>
2 struct DerivedFrom {
3       typedef Nulltype Base;
4 };
5
6 template <template <typename T> class Derived>
7 struct DerivedFrom<Derived<T> > {
8       typedef Nulltype Base;
9 };

(7) : error C2065: 'T' : undeclared identifier
(9) : error C2953: 'DerivedFrom<Derived>' : template class has already
been defined
(9) : see declaration of 'DerivedFrom<Derived>'
(9) : error C2753: 'DerivedFrom<Derived>' : partial specialization
cannot match argument list for primary template

Basically, I want DerivedFrom to work for template classes as well as
regular classes. Is this even possible?

Thanks,
Hasan.

      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

0
Reply chokidar (2) 9/24/2004 3:43:35 PM

chokidar wrote:
 > Hello,
 >
 > I get an error on Visual Studio 7.1 when I try to compile the
 > following code:
 >
 > 1 template <class T>
 > 2 struct DerivedFrom {
 > 3       typedef Nulltype Base;
 > 4 };
 > 5
 > 6 template <template <typename T> class Derived>
 > 7 struct DerivedFrom<Derived<T> > {
 > 8       typedef Nulltype Base;
 > 9 };
 >
 > (7) : error C2065: 'T' : undeclared identifier
 > (9) : error C2953: 'DerivedFrom<Derived>' : template class has already
 > been defined
 > (9) : see declaration of 'DerivedFrom<Derived>'
 > (9) : error C2753: 'DerivedFrom<Derived>' : partial specialization
 > cannot match argument list for primary template

I get an error message about Nulltype not being defined. ;-)

The important message is the first one: T is not declared.  Yes,
there's a T in line 6, but that's a (redundant) name for the template
parameter of the "Derived" parameter and *not* a parameter of
DerivedFrom.

If you add a second parameter to DerivedFrom, typename T, then lines
6-9 will become a valid partial specialisation of DerivedFrom that
applies to specialisations of templates with a single template type
parameter.

 > Basically, I want DerivedFrom to work for template classes as well as
 > regular classes. Is this even possible?

That depends on whether you mean template classes (e.g.
std::vector<int>) or class templates (e.g. std::vector).  Template
classes shouldn't need any special treatment.  Class templates are a
completely different kind of entity, and can't be handled by the same
template.  I don't see any way in the language to test whether a class
template is derived from any other class template, anyway, nor do I
see why that would be important.

-- 
Ben Hutchings
Reality is just a crutch for people who can't handle science fiction.

      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

0
Reply Ben 9/25/2004 10:23:30 AM


chokidar@earthlink.net (chokidar) writes:

 > I get an error on Visual Studio 7.1 when I try to compile the
 > following code:

The compiler is correct.


 > 1 template <class T>
 > 2 struct DerivedFrom {
 > 3       typedef Nulltype Base;
 > 4 };
 > 5
 > 6 template <template <typename T> class Derived>

Note that in this line, T is just a formal parameter in Derived. This

template <template <typename> class Derived>

is equivalent to your line 6.


Something like

template <typename T, template <typename> class Derived>

should work if you want specializations of Derived to be treated differently
than other classes.


 > 7 struct DerivedFrom<Derived<T> > {
 > 8       typedef Nulltype Base;
 > 9 };
 >
 > (7) : error C2065: 'T' : undeclared identifier
 > (9) : error C2953: 'DerivedFrom<Derived>' : template class has already
 > been defined
 > (9) : see declaration of 'DerivedFrom<Derived>'
 > (9) : error C2753: 'DerivedFrom<Derived>' : partial specialization
 > cannot match argument list for primary template
 >
 > Basically, I want DerivedFrom to work for template classes as well as
 > regular classes. Is this even possible?

Maybe I don't understand the problem, but the primary template alone
should be sufficient for this.

Can you give a specialization example for each of the two cases to clarify
things?

      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]
0
Reply Thomas 9/25/2004 10:30:43 AM

> 6 template <template <typename T> class Derived>
> 7 struct DerivedFrom<Derived<T> > {
> 8       typedef Nulltype Base;
> 9 };

Try

template <template <typename> class Derived, typename T>
struct DerivedFrom <Derived <T> > {
  typedef Nulltype Base;
};

> Basically, I want DerivedFrom to work for template classes as well as
> regular classes. Is this even possible?

The above formulation means DerivedFrom is specialized for all
template classes with a single type param.

E.g.

class A  { .. };
template <typename T> class B { .. };
template <typename T, typename U> class C { .. };

DerivedFrom <A> d0; // doesn't use above specialization
DerivedFrom <B <int> > d1; // uses above specialization
DerivedFrom <C <int, char> > d2; // doesn't use above specialization

Cheers,
Glen Low, Pixelglow Software
www.pixelglow.com

      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

0
Reply glenlow 9/25/2004 6:00:13 PM

chokidar wrote:
> Hello,
> 
> I get an error on Visual Studio 7.1 when I try to compile the
> following code:
> 
> 1 template <class T>
> 2 struct DerivedFrom {
> 3       typedef Nulltype Base;
> 4 };
> 5
> 6 template <template <typename T> class Derived>
> 7 struct DerivedFrom<Derived<T> > {
> 8       typedef Nulltype Base;
> 9 };
> 

The T in line 6 is used only to give a name to the template argument of 
Derived and because of that it's completely ignored by the compiler. 
That's exactly the same thing happening in function prototypes:

   void foo(int a);
   void foo(int bar);
   void foo(int);

those are all valid prototypes of the same function. So your code can 
also be written as:

   template <template <typename> class Derived>
   struct DerivedFrom<Derived<T> > {
     typedef Nulltype Base;
   };

As you can see, T has been used without being previously declared and 
the compiler rightly complains about that. But if you declare it first, 
everything's ok:

   template <typename T, template <typename> class Derived>
   struct DerivedFrom<Derived<T> > {
     typedef Nulltype Base;
   };

Hope it helps,

Alberto

      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]

0
Reply Alberto 9/25/2004 6:00:58 PM

>I get an error on Visual Studio 7.1 when I try to compile the
>following code:
>template <template <typename T> class Derived>
>struct DerivedFrom<Derived<T> > {
>       typedef Nulltype Base;
>};

T, as declared in your example as a parameter in a template template
parameter declaration, is not (and cannot be) used in the template
class definition (struct DerivedFrom<Derived<T /*this is bad*/> >).  To
fix your problem, create another template parameter in the parameter
list of your specialization declaration to act as the argument when
using the template template parameter.

template
<
typename T,            // <-- new parameter here
template <typename>    // <-- notice no 'T' here
class Derived
>
struct DerivedFrom<Derived<T> > {   // Ok now!
typedef Nulltype Base;
};

I suggest that you ommit parameter names in a template template
parameter list (as I did above...<typename>) to enforce the fact that
they are not used.

-dave


      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]
0
Reply Dave 9/25/2004 6:35:42 PM

So lets say I change the declarations to

// here's Nulltype :-)
struct Nulltype {};

template <class T>
struct DerivedFrom {
    typdef Nulltype Base;
};

template <template <typename> Derived>
struct DerivedFrom<Derived> {
    typedef Nulltype Base;
};

And lets say we have this class hierarchy

class A {
    static void foo();
};

template <>
struct DerivedFrom<B> {
    typedef A Base;
};

class B : class A {
    static void foo();
};

template <>
struct DerivedFrom<C> {
    typedef B Base;
};

template <class T>
class C : class B {
    static void foo();
};

I want to be able to write this kind of code:

template <class T>
void call_foo() {
    T::foo();
    call_foo<DerivedFrom<T>::Base>();
}

template <>
void call_foo<Nulltype>() {
    return;
}

int main() {
    call_foo<C>();
    return 0;
}

So to get this to work I need to get this to work:

template <class T>
class C : class B {
    static void foo();
};

I hope this clarifies my problem. Thank you for the help.

Hasan.

Thomas Maeder <maeder@glue.ch> wrote in message news:<m2llezr5db.fsf@madbox2.local>...
 > chokidar@earthlink.net (chokidar) writes:
 >
 >  > I get an error on Visual Studio 7.1 when I try to compile the
 >  > following code:
 >
 > The compiler is correct.
 >
 >
 >  > 1 template <class T>
 >  > 2 struct DerivedFrom {
 >  > 3       typedef Nulltype Base;
 >  > 4 };
 >  > 5
 >  > 6 template <template <typename T> class Derived>
 >
 > Note that in this line, T is just a formal parameter in Derived. This
 >
 > template <template <typename> class Derived>
 >
 > is equivalent to your line 6.
 >
 >
 > Something like
 >
 > template <typename T, template <typename> class Derived>
 >
 > should work if you want specializations of Derived to be treated differently
 > than other classes.
 >
 >
 >  > 7 struct DerivedFrom<Derived<T> > {
 >  > 8       typedef Nulltype Base;
 >  > 9 };
 >  >
 >  > (7) : error C2065: 'T' : undeclared identifier
 >  > (9) : error C2953: 'DerivedFrom<Derived>' : template class has already
 >  > been defined
 >  > (9) : see declaration of 'DerivedFrom<Derived>'
 >  > (9) : error C2753: 'DerivedFrom<Derived>' : partial specialization
 >  > cannot match argument list for primary template
 >  >
 >  > Basically, I want DerivedFrom to work for template classes as well as
 >  > regular classes. Is this even possible?
 >
 > Maybe I don't understand the problem, but the primary template alone
 > should be sufficient for this.
 >
 > Can you give a specialization example for each of the two cases to clarify
 > things?

      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]
0
Reply chokidar 9/26/2004 9:39:08 AM

chokidar@earthlink.net (chokidar) writes:

Please next time throw the code at a compiler before posting. There are
a bunch of errors in your code that a compiler would have caught.

> So lets say I change the declarations to
>
> // here's Nulltype :-)
> struct Nulltype {};
>
> template <class T>
> struct DerivedFrom {
>     typdef Nulltype Base;

typedef Nulltype Base;

> };
>
> template <template <typename> Derived>

template <template <typename> class Derived>

> struct DerivedFrom<Derived> {
>     typedef Nulltype Base;
> };

But this will not work.

DerivedFrom is a template whose parameter is a type. You can't specialize
it for a class template; a class template is not a type.

What you can do is something like

template <typename T, template <typename> class Derived>
struct DerivedFrom< Derived<T> > {
    typedef Nulltype Base;
};


> And lets say we have this class hierarchy
>
> class A {
>     static void foo();

foo is private. You won't be able to call it from call_foo().

> };
>
> template <>
> struct DerivedFrom<B> {
>     typedef A Base;
> };
>
> class B : class A {

class B : public A {

>     static void foo();

foo is private. You won't be able to call it from call_foo().

> };

The definition of B has to precede the specialization of DerivedFrom for B.


> template <>
> struct DerivedFrom<C> {
>     typedef B Base;
> };

C is a template, as is DerivedFrom above. What about

template <typename T>
struct DerivedFrom< C<T> > {
    typedef B Base;
};


> template <class T>
> class C : class B {

class C : public B

>     static void foo();

foo is private. You won't be able to call it from call_foo().

> };

The definition of C has to precede the specialization of DerivedFrom for
intances of C.


> I want to be able to write this kind of code:
>
> template <class T>
> void call_foo() {
>     T::foo();
>     call_foo<DerivedFrom<T>::Base>();

    call_foo<typename DerivedFrom<T>::Base>();

> }
>
> template <>
> void call_foo<Nulltype>() {
>     return;
> }
>
> int main() {
>     call_foo<C>();

Which foo() should be called by call_foo() as a result of this call?


>     return 0;
> }

Again, call_foo is a function template whose template parameter is a type.
C is a template, though. This will not work.

To make the main() function compile, you can

* overload call_foo for templates like C

template <template <typename> class T>
void call_foo()
{
}

I find it hard to figure out which foo() to call from there, though.


* instantiate call_foo on a specialization of C rather than C itself:

call_foo< C<B> >();

      [ See http://www.gotw.ca/resources/clcm.htm for info about ]
      [ comp.lang.c++.moderated.    First time posters: Do this! ]
0
Reply Thomas 9/26/2004 4:05:50 PM

7 Replies
266 Views

(page loaded in 3.728 seconds)

Similiar Articles:













7/23/2012 4:27:55 PM


Reply: