4

In the following setup, how can I make it so that I can refer to the name Bar inside the derived class Derived<T>?

template <typename T> struct Foo
{
    template <typename U> struct Bar { };
};

template <typename T> struct Derived : Foo<T>
{
    // what goes here?

    Bar<int> x;  // Error: 'Bar' does not name a type
};

I've tried using Foo<T>::Bar;, but that doesn't help. Is there any sort of using declaration that can make the name of a nested base template known to the derived class, so that I can keep the simple de­cla­ration Bar<int> x?

I know that I can say typename Foo<T>::template Bar<int> x;, but I have a lot of those cases and I don't want to burden the code needlessly with so much verbosity. I also have a lot of distinct "ints", so a typedef for each nested-template instance is not feasible, either.

Also, I cannot use GCC 4.7 at this point nor C++11, and would thus like a "traditional" solution without template aliases.

Kerrek SB
  • 464,522
  • 92
  • 875
  • 1,084

3 Answers3

6

In C++11 you can use an alias template:

template <typename T> struct Derived : Foo<T>
{
  template<typename X> using Bar = typename Foo<T>::template Bar<X>;
  Bar<int> x;
};

Edit

The traditional solution is what you're already said, typename Foo<T>:template Bar<int>, or to emulate a "template typedef"

template <typename T> struct Derived : Foo<T>
{
  template<typename X>
    struct Bar
    { typedef typename Foo<T>::template Bar<X> type; };
  typename Bar<int>::type x;
};

One of the reasons for adding alias templates to the language is they support things which can't be expressed easily in C++03.

Jonathan Wakely
  • 166,810
  • 27
  • 341
  • 521
1

Declaring x as Foo<T>::Bar<int> x; simply works for me.

miloszmaki
  • 1,635
  • 15
  • 21
  • I think, that shouldn't work! If it does, then I'm wondering how come. Maybe, the compiler has bug? – Nawaz May 17 '12 at 17:52
  • @Nawaz: Why? It compiles in Dev-C++ 4.9.9.2. – miloszmaki May 17 '12 at 17:53
  • I don't want to change the declarations. I really *want* to be able to say just `Bar x;`. – Kerrek SB May 17 '12 at 17:54
  • 1
    miloszmaki: `Bar` is a dependent type, so it shouldn't work without `typename`. – Nawaz May 17 '12 at 17:54
  • 2
    @miloszmaki : That's not a compiler, it's a (terrible) IDE that comes bundled with a downright ancient compiler (GCC 3.4.2). – ildjarn May 17 '12 at 18:02
  • @miloszmaki : Right -- as others have noted, your declaration is missing `typename` (because `Foo` is a dependent type) and `template` (because `Bar` is a template nested inside of a template). A conforming compiler would reject this declaration. – ildjarn May 17 '12 at 18:39
0

This works:

template <typename T> struct Foo
{
    template <typename U> struct Bar { };
};

template <typename T> struct Derived : Foo<T>
{
    template<class W>
    struct Bar : public Foo<T>::template Bar<W> {

    };

    Bar<int> x;  
};

IDK if that's what you're looking for, but it does compile.

mfontanini
  • 21,410
  • 4
  • 65
  • 73
  • 1
    That's not exactly the same thing. It's close, but even trivial things that should work if the types were the same don't in this case: `Derived d; Foo::Bar y; d.x = y;` – cvoinescu May 17 '12 at 18:40
  • That gives a nicer syntax than the "template typedef" in my answer, but it's worth noting that `Foo::Bar` and `Derived::Bar` are not actually the same type. That might not matter, but it could do in some cases e.g. templates or overloads that work with `Foo::Bar` might not match `Derived::Bar` and so the wrong overload gets used. (Edit: I see cvoinescu said the same thing, but more clearly.) – Jonathan Wakely May 17 '12 at 18:41
  • @cvoinescu Yes, it doesn't work in that case. However, if the class is used only internally inside `Derived`, then it will work(though I don't know if this is the case). I just wanted to point out a shorter syntax than the one used to declare a template typedef. – mfontanini May 17 '12 at 18:48