Propagating 'typedef' from based to derived class for 'template'
Asked Answered
T

7

73

I'm trying to define base class, which contains typedef's only.

template<typename T>
class A
{
public:
    typedef std::vector<T> Vec_t;
};


template<typename T>
class B : public A<T>
{
private:
    Vec_t v;  // fails - Vec_t is not recognized
};

Why in B I receive an error that Vec_t is not recognized and I need to write it explicitly?

typename A<T>::Vec_t v;
Tavis answered 29/10, 2009 at 11:21 Comment(3)
Exact duplicate: #1568230Ready
Well, not really an exact duplicate since the post you mention talks about a method while this one talks about a type.Slut
typename A::Vec_t v; is fine. No need for <T> thereFaubert
R
49

I believe that this question is duplicate, but I cannot find it now. C++ Standard says that you should fully qualify name according to 14.6.2/3:

In the definition of a class template or a member of a class template, if a base class of the class template depends on a template-parameter, the base class scope is not examined during unqualified name lookup either at the point of definition of the class template or member or during an instantiation of the class template or member.

UPD: I found duplicate finally: here it is.

Ready answered 29/10, 2009 at 11:54 Comment(4)
By the way, it always bug me that I had to 're-typedef' everything... it's not pleasant, not pleasant at all.Slut
btw you don't need all the template arguments and all, when qualifying. Because of the injected class name, it suffices to write typename B::Vec_tGentile
@JohannesSchaub-litb I'm trying to do it as you said, but I'm getting errors if I don't specify the template parameters for B. (B is not a class, namespace, or enumeration)Dawn
@GonzaloSolera I am having your same error result, but only on one of my platforms, one with an older C++ standard. I wonder if the need to fully qualify changed at some point?Jardena
L
44

There is something called dependent and nondependent names in case of templates.

If name depends on template parameter T its dependent name and others those do not depend on parameter T are independent names.

Here's the rule: the compiler does not look in dependent base classes (like A) when looking up nondependent names (like Vec_t). As a result, the compiler does not know they even exist let alone are types.

Compiler cannot assume that Vec_t is a type until it knows T because There is a potential specialization of A<T> where A<T>:: Vec_t is a is a data member

So the solution is use typename

 typename A<T>::Vec_t v;  ← good

I recommend you go through this https://isocpp.org/wiki/faq/templates#nondependent-name-lookup-types.

Old (broken) link: http://www.parashift.com/c++-faq-lite/templates.html#faq-35.18

Leatrice answered 29/10, 2009 at 11:49 Comment(2)
Yours was the only answer that seemed to provide a solution in addition to an explanation. Thank you.Clementius
I offer you a +1 if you notify me that you have corrected the link.Bricole
C
10

For completeness, here's how you could mitigate this nuisance a little, either:

  • re-typedef those types in derived classes, or better - as with methods -
  • just import those names in the derived class scope with a using declaration:

template<typename T>
class A
{
public:
    typedef std::vector<T> Vec_t;
};


template<typename T>
class B : public A<T>
{
public:
    using typename A<T>::Vec_t;
    // .........

private:
    Vec_t v;
};

It can be useful if you have more than one mentioning of the inherited typedef in the derived class. Also you don't need to add typename each time with this.

Centerpiece answered 19/9, 2018 at 16:47 Comment(1)
You have a typo. using typename A::Vec_t; should be using typename A<T>::Vec_t;Bugaboo
Q
8

Because the compiler's not certain that Vec_t names a type. For example, A<T> might be specialized for T=int to not have that particular typedef.

Quizzical answered 29/10, 2009 at 11:38 Comment(1)
For T a type variable, A<T> is merely forward declared, it does not have a definition. Only A<t> where t is a type (not type variable) can be defined (by specializing a template definition or by an explicit specialisation). IOW, even if you removed template explicit and partial specialisations from C++ (and but not change anything else), it still would not be correct.Mispleading
R
2

You need to explicitly qualify the use of Vec_t because the compiler does not know where Vec_t comes from.

It cannot assume anything about the structure of A, since the class template A may be specialized. The specialization may include a Vec_t which is not a typedef, or it may not even include a member Vec_t at all.

Reareace answered 29/10, 2009 at 11:40 Comment(0)
G
1

Vec_t is not a dependent name, and the compiler needs to know what it is without instantiating any templates (base class in this case). It is really no different from:

template <class T>
class X
{
    std::string s;
}

Here as well the compiler needs to know about std::string even if X is not instantiated, since the name does not depend on the template argument T (as far as the compiler can assume).

All in all, typedefs in a template base class seem rather useless for use in derived class. The typedefs are useful for the user, however.

Gaulish answered 29/10, 2009 at 11:44 Comment(1)
do you mean class X : T { here?Mispleading
N
1

This concept can be associated with how we use std::vector<T>. For example, if we have a std::vector<int> Foo. Now, we decide to use any of it's member types, lets say an iterator. In this scenario we explicitly mention

std::vector<int>::iterator foo_iterator;

Similarly in your case, in order to use a public member type Vec_t of template <typename T> class A, you need to explicitly declare it as

A<T>::Vec_t v;
OR
A<int>::Vec_t int_type;
Naominaor answered 21/2, 2018 at 17:1 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.