tags:

views:

247

answers:

4

Consider the following:

template <typename T>
class Base {
  public:
    template <typename U>
    class Nested { };
};

template <typename T>
class Derived : public Base<T> {
  public:
    //How do we typedef of redefine Base<T>::Nested?
    using Base<T>::Nested; //This does not work
    using Base<T>::template<typename U> Nested; //Cannot do this either
    typedef typename Base<T>::template<typename U> Nested Nested; //Nope..

    //now we want to use the Nested class here
    template <typename U>
    Class NestedDerived : public Nested { };

    //or like this:
    Nested<int> nestedVar; // obviously does not work
};

How to use the templated Nested class in the Derived class? Is this possible to do in current version of C++ standard?

A: 

Try this:

template <typename T>
class Base {
  public:
    template <typename U>
    class Nested { };
};

template <typename T>
class Derived : public Base<T> {
  public:
    //How do we typedef of redefine Base<T>::Nested?
    //using Base<T>::Nested; //This does not work
  //using Base<T>::template<typename U> Nested; //Cannot do this either
  //typedef typename Base<T>::template<typename U> Nested Nested; //Nope..

    //now we want to use the Nested class here
  template <typename U>
  class NestedDerived : public Base<T>::template Nested<U> { };
};

int main()
{
  Base<int>::Nested<double> nested;

  Derived<int>::NestedDerived<double> nested_derived;

  return 0;
}

Compiled fine using gcc 4.3.3 on slackware 13

coelhudo
Sorry, but this is not what I am asking. What I want to know is, is it possible to typedef or using the `public Base<T>::template Nested<U>` inside the `Derived` class, because that type will be used in lots of places.
leiiv
Ok, sorry, I will try to find a suitable answer
coelhudo
A: 

I'm still not 100% sure what you want, but you could try.
This compiled on Visual Studio

template <typename T>
class Base {
  public:
    template <typename U>
    class Nested { };
};

template <typename T>
class Derived : public Base<T> {
  public:
    //now we want to use the Nested class here
    template <typename U>
    class NestedDerived : public Nested<U> { };
};

int _tmain(int argc, _TCHAR* argv[])
{
Base<int>::Nested<double> blah2;
Derived<int>::NestedDerived<int> blah;

return 0;
}
Craig
this can also use Derived<int>::Nested<float> blah3;
Craig
ah good ol' VS.. g++ 4.4.1 does not let me do that..
leiiv
What is the difference between what I did and what Craig did? I really didn`t spotted :/
coelhudo
The problem is you can't use the Nested definition just like that inside Derived class, you have to use a fully qualified name.
leiiv
onyl difference i see is this line class NestedDerived : public Base<T>::template Nested<U> { };
Craig
Is there a different semantic?
coelhudo
The difference is coelhudo's solution compiles on gcc/g++, but still does not answer my question
leiiv
can't you just use class NestedDerived : public Base::Nested<U>. The problem is that it runs both Nested and DerivedNested. I'm sure you will find someone here who will have tried this before, personally i haven't needed to yet so i haven't had much of a try.
Craig
I can just move the Nested class out of Base, it is easier that way I guess.
leiiv
+2  A: 

This seems to work:
(EDIT: added some more lines to show the first template statement. And thanks to Samir Talwar for correcting my formatting!)

template <typename T, typename U> 
class Derived : public Base<T> { 
  public: 
    typedef typename Base<T>::template Nested<U> Nested;

    class NestedDerived : public Nested { }; 

    Nested nestedVar;
};
Beta
But now users always have to specify a second template argument for `Derived`.
Georg Fritzsche
Yes, and one Derived cannot have more than one type of NestedDerived. It is a serious limitation, but otherwise I don't see any way to have NestedDerived make use of Base::Nested.
Beta
+6  A: 

Actually using works as advertised, it just doesn't get rid of the dependent-name issue in the template and it can't currently alias templates directly (will be fixed in C++0x):

template <class T>
struct Base {
    template <class U> struct Nested {};
};

template <class T>
struct Derived : Base<T> {
    using Base<T>::Nested;

    // need to prefix Nested with template because
    // it is a dependent template:
    struct X : Base<T>::template Nested<int> {};

    // same here:
    template<class U>
    struct Y : Base<T>::template Nested<U> {};

    // data member, typename is needed here:
    typename Base<T>::template Nested<int> data;
};

void f() { 
    Derived<int>::Nested<int> n; // works fine outside
}

There is another possible gotcha when using Derived<T>::Nested in templates, but again that is a dependent-name issue, not inheritance-related:

template<class T>
void g() {
    // Nested is a dependent type and a dependent template, thus
    // we need 'typename' and 'template':
    typedef typename Derived<T>::template Nested<int> NestedInt;
}

Just remember that names that depend on template arguments have to be

  • prefixed with typename if its a dependent type: typename A<T>::B
  • directly prefixed with template if its a dependent template: A<T>::template f<int>()
  • both if both: typename A<T>::template B<int>
  • typename is illegal in base-class-lists: template<class T> struct A : B<T>, C<T>::template D<int> {};
Georg Fritzsche
Can you give example how to use the Nested type for a data member of Derived class? If we still have to use `Base<T>::` , then would the `using Base<T>::Nested` be useless?
leiiv
Will do. `using Base<T>::Nested` is not useless though, it is used in `f()` and `g()` - without the `using` declaration, you would have to access `Nested` via `Base` in `f()`.
Georg Fritzsche
Thank you gf, that's very helpful.
leiiv
Nice answer. +1! Worth pointing out that there is another version `using typename` that is used if `Nested` is a type name (and C++0x will then classify `Nested` in the scope of `Derived` as a type-name (C++03 missed this classification, even tho supporting `using typename`!)). There is, sadly, no way to just write `using Base<T>::template Nested;` to use `Nested` as a template-name in the derived class (neither in C++03 nor in C++0x. In C++0x you would have to use an alias-declaration like you are saying).
Johannes Schaub - litb
(the defect report for all this is http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#11 )
Johannes Schaub - litb