Asked  6 Months ago    Answers:  5   Viewed   26 times

Possible Duplicate:
Officially, what is typename for?
Where and why do I have to put the template and typename keywords?

consider the code below:

template<class K>
class C {
    struct P {};
    vector<P> vec;
    void f();
};

template<class K> void C<K>::f() {
    typename vector<P>::iterator p = vec.begin();
}

Why is the "typename" keyword necessary in this example? Are there any other cases where "typename" must be specified?

 Answers

22

Short answer: Whenever referring to a nested name that is a dependent name, i.e. nested inside a template instance with unknown parameter.

Long answer: There are three tiers of entities in C++: values, types, and templates. All of those can have names, and the name alone doesn't tell you which tier of entity it is. Rather, the information about the nature of a name's entity must be inferred from the context.

Whenever this inference is impossible, you have to specify it:

template <typename> struct Magic; // defined somewhere else

template <typename T> struct A
{
  static const int value = Magic<T>::gnarl; // assumed "value"

  typedef typename Magic<T>::brugh my_type; // decreed "type"
  //      ^^^^^^^^

  void foo() {
    Magic<T>::template kwpq<T>(1, 'a', .5); // decreed "template"
    //        ^^^^^^^^
  }
};

Here the names Magic<T>::gnarl, Magic<T>::brugh and Magic<T>::kwpq had to be expliciated, because it is impossible to tell: Since Magic is a template, the very nature of the type Magic<T> depends on T -- there may be specializations which are entirely different from the primary template, for example.

What makes Magic<T>::gnarl a dependent name is the fact that we're inside a template definition, where T is unknown. Had we used Magic<int>, this would be different, since the compiler knows (you promise!) the full definition of Magic<int>.

(If you want to test this yourself, here's a sample definition of Magic that you can use. Pardon the use of constexpr in the specializaation for brevity; if you have an old compiler, feel free to change the static member constant declaration to the old-style pre-C++11 form.)

template <typename T> struct Magic
{
  static const T                    gnarl;
  typedef T &                       brugh;
  template <typename S> static void kwpq(int, char, double) { T x; }
};
template <> struct Magic<signed char>
{
  // note that `gnarl` is absent
  static constexpr long double brugh = 0.25;  // `brugh` is now a value
  template <typename S> static int kwpq(int a, int b) { return a + b; }
};

Usage:

int main()
{
  A<int> a;
  a.foo();

  return Magic<signed char>::kwpq<float>(2, 3);  // no disambiguation here!
}
Tuesday, June 1, 2021
 
iceduck
answered 6 Months ago
11

No difference at all. I prefer first one (mostly), but that is my personal taste. The language doesn't make any difference between them.

For template parameters, the keywords typename and class are equivalent. §14.1.2 says:

There is no semantic difference between class and typename in a template-parameter.


If both are same,then why do we have them both if one is enough?

Stan Lippman explains this in his article:

Why C++ Supports both Class and Typename for Type Parameters?

Friday, August 6, 2021
 
borrible
answered 4 Months ago
95

You can create a helper method

public static T as(Object o, Class<T> tClass) {
     return tClass.isInstance(o) ? (T) o : null;
}

User user = as(obj, User.class);
Thursday, August 12, 2021
 
Dobz
answered 4 Months ago
71

There's nothing so arcane about it. Just take out your template template parameters from the original template:

template <typename> class Cont

Any class template with a single type argument fits, such as

template <typename T>
class A {
public:
  A(T t) : t_(t) {}
  T get() { return t_; }
private:
  T t_;
};

And you would use your original template as

Stack<int, A> s;
Thursday, August 12, 2021
 
ajjumma
answered 4 Months ago
58

The name before the scope operator :: must always be a namespace or class (or enumeration) name, and namespace names can't be dependent. So you don't have to tell the compiler that this is a class name.


I'm not just making this up, the standard says (section [temp.res]):

A qualified name used as the name in a mem-initializer-id, a base-specifier, or an elaborated-type-specifier is implicitly assumed to name a type, without the use of the typename keyword. In a nested-name-specifier that immediately contains a nested-name-specifier that depends on a template parameter, the identifier or simple-template-id is implicitly assumed to name a type, without the use of the typename keyword. [ Note: The typename keyword is not permitted by the syntax of these constructs. — end note ]

T::, T::Type::, and T::Type::Type:: are nested-name-specifiers, they do not need to be marked with typename.

This section clearly could have, and arguably should have, included the type-specifier of a typedef declaration in the list of exemptions. But remember that type-specifiers can get really complicated, especially in typedef declarations. Right now it's quite possible to need the typename keyword multiple times in a typedef type-specifier, so a lot more analysis would be needed to convince me that typename is never necessary in a typedef.

In typedef typename T::Type::Type Type, T::Type::Type requires use of the typename keyword, because its nested-name-specifier (T::Type::) is a dependent name, and the standard says (same section):

When a qualified-id is intended to refer to a type that is not a member of the current instantiation (14.6.2.1) and its nested-name-specifier refers to a dependent type, it shall be prefixed by the keyword typename, forming a typename-specifier. If the qualified-id in a typename-specifier does not denote a type, the program is ill-formed.

Tuesday, September 28, 2021
 
Eduardo Sousa
answered 2 Months ago
Only authorized users can answer the question. Please sign in first, or register a free account.
Not the answer you're looking for? Browse other questions tagged :
 
Share