Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why I can not simply use types defined in base class if both classes are templates?

Why I can not simply use types defined in base class if both classes are templates? Is there some rule about searching of template members? Here is the simplest example I could deduce:

struct iA {
    using type = int;
};
template <class T> struct tA {
    using type = T;
};

struct iB1 : iA {
    void f(type i) {}
};
struct iB2 : tA<int> {
    void f(type i) {}
};
template <class T> struct tB1 : iA {
    void f(type i) {}
};
template <class T> struct tB2 : tA<int> {
    void f(type i) {}
};
template <class T> struct tB3 : tA<T> {
    // void f(type i) {} // error: 'type' has not been declared
    void f(typename tA<T>::type i) {}
};

int main() {}

Of course, I can just add typename tA<T>::, but is there a more elegant solution?

like image 589
se0808 Avatar asked Mar 01 '15 09:03

se0808


People also ask

Can a class be both a base class and a derived class?

A derived class can have only one direct base class.

What is the difference between class template and template class?

An individual class defines how a group of objects can be constructed, while a class template defines how a group of classes can be generated. Note the distinction between the terms class template and template class: Class template. is a template used to generate template classes.

What are templates How are templates used to define classes and functions?

Class Templates like function templates, class templates are useful when a class defines something that is independent of the data type. Can be useful for classes like LinkedList, BinaryTree, Stack, Queue, Array, etc. Following is a simple example of a template Array class.

Can a template class inherit from a non template class?

Deriving from a non-template base classIt is quite possible to have a template class inherit from a 'normal' class. This mechanism is recommended if your template class has a lot of non-template attributes and operations. Instead of putting them in the template class, put them into a non-template base class.


1 Answers

The problem is that the base class is dependent, and thus its scope is only examined when we are looking up dependent names. [temp.dep]/3:

In the definition of a class or class template, if a base class 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.

The reason for this rule is that there might be e.g. specializations of the base class template. Since we don't know the specific template arguments at definition time, we cannot inspect the base classes scope.

type isn't dependent and thus will not be looked up in the dependent base tA<T>. However, because it isn't dependent, a declaration for it must be available at definition time, [temp.res]/10:

If a name does not depend on a template-parameter (as defined in 14.6.2), a declaration (or set of declarations) for that name shall be in scope at the point where the name appears in the template definition; the name is bound to the declaration (or declarations) found at that point and this binding is not affected by declarations that are visible at the point of instantiation.


If you need to use type frequently in the derived class, using declarations can help.

template <class T> struct tB3 : tA<T> {
    using typename tA<T>::type;
    void f(type i) {}
};

Demo.

like image 121
Columbo Avatar answered Oct 18 '22 20:10

Columbo