2

A question regarding template disambiguator was given here:

template disambiguator

and in the answer we can read:

ISO C++03 14.2/4

When the name of a member template specialization appears after . or -> in a postfix-expression, or after nested-name-specifier in a qualified-id, and the postfix-expression or qualified-id explicitly depends on a template-parameter (14.6.2), the member template name must be prefixed by the keyword template. Otherwise the name is assumed to name a non-template.

Now here comes my conrete example that I don't quite understand:

template <class T>
class Base {
  public:


  template <int v>
    static int baseGet() {return v;}

  class InnerA {
    public:

    template <int v>
      static int aget() {return v;}

  };

  class InnerB {
    public:
      typedef Base BaseType;
      typedef BaseType::InnerA OtherType;

      template <int v>
        static int baseGet() {return BaseType::baseGet<v>();} //(A)

      template <int v>
        static int aget() {return OtherType::aget<v>();} //(B)
  };
};

It obviously fails to compile. You need template in the line (B): OtherType::template aget<v>();. However, both g++ (4.4.3) and clang++ (2.9) don't complain about the lack of template in the line (A). Why? BaseType depends on the type T, does it not? Is it a small depart from the standard by those compilers, or do I misunderstand something in the standard?

Community
  • 1
  • 1
CygnusX1
  • 20,968
  • 5
  • 65
  • 109

3 Answers3

8

They implement the C++0x specification, where Base is the current instantiation. And C++0x allows to omit template keyword in such a case. Since BaseType is a typedef for Base, when you say BaseType, that names the current instantiation too.

To quote the spec, since you seem to be interested in spec refs

A name is a member of the current instantiation if it is [...]

  • A qualified-id in which the nested-name-specifier refers to the current instantiation and that, when looked up, refers to at least one member of the current instantiation or a non-dependent base class thereof.

and

A name refers to the current instantiation if it is [...]

  • in the definition of a [...] nested class of a class template, [...], the injected-class-name (Clause 9) of the class template or nested class

and (the modified 14.2/4 that you quoted)

[...] or the nested-name-specifier in the qualified-id refers to a dependent type, but the name is not a member of the current instantiation (14.6.2.1), the member template name must be prefixed by the keyword template. [...]


Note: In C++03 your code is ill-formed because both BaseType and OtherType are dependent. The spec says:

A type is dependent if it is [...]

  • a template parameter
  • a qualified-id with a nested-name-specifier which contains a class-name that names a dependent type
  • a template-id in which either the template name is a template parameter or any of the template arguments is a dependent type

(note that Base is equivalent to Base<T>, which is the base on which Base and BaseType::InnerA are dependent types).

Note that "explicitly depends" in your quote is a pre-standard term, and was gotten rid of fairly lately (I believe it was at December1996). It basically meant (in this context) a qualified-id in which the qualifier is dependent or a class member access (a->x / a.x) where the a was dependent. After "explicitly depends" was removed from the draft, it was still lurking around at some places, and even C++0x has still references to "explicitly depends" in a note at 14.6.2p2:

the base class name B<T>, the type name T::A, the names B<T>::i and pb->j explicitly depend on the template-parameter.

Johannes Schaub - litb
  • 496,577
  • 130
  • 894
  • 1,212
1

Because OtherType is a nested dependent name while BaseType is not a nested type to begin with.

You need to use template for nested dependent types.

The keywords here are:

  • Dependent Type
  • Nested Type

If a type is both, then you've to use template.

  • OtherType is both dependent type (it depends on T) as well as nested type
  • BaseType is only dependent type (it depends on T). Its not a nested type.
Nawaz
  • 353,942
  • 115
  • 666
  • 851
  • According to http://stackoverflow.com/questions/4103756/what-is-a-nested-name-specifier both `BaseType::` and `OtherType::` are nested-name-specifiers. The fact that you actually specify a namespace already within your scope does not matter... or? – CygnusX1 Jun 23 '11 at 15:44
  • @Cygnus: Types defined at namespace level are not called *nested* types. – Nawaz Jun 23 '11 at 15:45
0

BaseType does depend on the type T- but so does InnerB. In effect, from the perspective of any code inside BaseType<T>, it does not depend on T.

Puppy
  • 144,682
  • 38
  • 256
  • 465
  • Since I am inside of `Base` and you say that it does not depend on `T` - then why do I need `template` in line (B)? – CygnusX1 Jun 23 '11 at 15:35
  • @CygnusX1: It's because you're accessing another inner class. Inner classes are treated very strangely in C++03 and the rules about them don't make much logical sense. – Puppy Jun 23 '11 at 15:46