Day_Dreamer
Day_Dreamer

Reputation: 3373

refering to Templates c++

Considering Template Class when do we have to refer explicitly to template, and when the compiler "understands that we meant it"

considering the following occurences:

1) function return value & arguements

2) variable declaration inside function

3) namespace SomeClass<T>:: vs. SomeClass::

Is there any rule? I saw sometimes the use is of:

SomeClass

and sometimes: SomeClass<T>

and I didn't get the rule

Upvotes: 5

Views: 138

Answers (2)

Columbo
Columbo

Reputation: 60999

The standard describes all scenarios in [temp.local]:

  1. Like normal (non-template) classes, class templates have an injected-class-name (Clause 9). The injected-class-name can be used as a template-name or a type-name. When it is used with a template-argument-list, as a template-argument for a template template-parameter, or as the final identifier in the elaborated-type-specifier of a friend class template declaration, it refers to the class template itself. Otherwise, it is equivalent to the template-name followed by the template-parameters of the class template enclosed in <>.

  2. Within the scope of a class template specialization or partial specialization, when the injected-class-name is used as a type-name, it is equivalent to the template-name followed by the template-arguments of the classtemplate specialization or partial specialization enclosed in <>.

[ Example:

template<template<class> class T> class A { };
template<class T> class Y;
template<> class Y<int> {
  Y* p;                             // meaning Y<int>
  Y<char>* q;                       // meaning Y<char>
  A<Y>* a;                          // meaning A<::Y>
  class B {
    template<class> friend class Y; // meaning ::Y
  };
};

—end example ]

This only works inside the class template (i.e. the scope of the injected-class-name), and only if the name is accessed from a corresponding scope:

When the normal name of the template (i.e., the name from the enclosing scope, not the injected-class-name) is used, it always refers to the class template itself and not a specialization of the template. [ Example:

template<class T> class X {
  X* p;             // meaning X<T>
  X<T>* p2;
  X<int>* p3;
  ::X* p4;         // error: missing template argument list
                   // ::X does not refer to the injected-class-name
};

—end example ]

And for base classes, where the base is not dependent:

A lookup that finds an injected-class-name (10.2) can result in an ambiguity in certain cases (for example, if it is found in more than one base class). If all of the injected-class-names that are found refer to specializations of the same class template, and if the name is used as a template-name, the reference refers to the class template itself and not a specialization thereof, and is not ambiguous. [ Example:

template <class T> struct Base { };
template <class T> struct Derived: Base<int>, Base<char> {
  typename Derived::Base b;             // error: ambiguous
  typename Derived::Base<double> d;     // OK
};

—end example ]

We can modify the example slightly to show what would be valid:

template <class T> struct Base { };
template <class T> struct Derived: Base<char> {
  typename Derived::Base b;             // Ok: b refers to Base<char>
};

Upvotes: 0

danielschemmel
danielschemmel

Reputation: 11126

Class template parameters may only be omitted inside the implementation of that class, where they implicitly add the appropriate template specifiers to the class and when referring to a non-dependent base class (non-dependent as in "does not reuse any template arguments"). For example:

template<typename T, typename U>
class C { /* here C is the same as C<T, U> */ };

template<typename T>
class C<void, T> { /* here C is the same as C<void, T> */ };

template<>
class C<void, void> { /* here C is the same as C<void, void> */ };

template<typename> struct Base { };

struct DerivedA : Base<void>
{ /* here Base is the same as Base<void> */ };

template<typename T>
struct DerivedB : Base<T>
{ /* here Base is invalid, since Base<T> depends on a template argument */ };

Function templates may have their template parameters omitted, if they can be deduced from their arguments:

template<typename T>
void f(T f);

f(3); // equivalent to f<int>(3) if no other overload exists

Additionally, there are default template arguments, which leads to something really funky:

template<typename T = void>
class D
{
    // Here D is D<T>, but D<> is D<void> instead!
};

Upvotes: 3

Related Questions