0

I try to compile the following C++ code:

struct A {
    template< bool x >
    bool fun() {
        return x;
    }
};

template< typename T >
struct B {
    struct A2 {
        template< bool x >
        bool fun() {
            return x;
        }
    };

    void test() {
        A a;
        A2 a2;
        a.fun< true >();
        a2.fun< true >();
    }
};

The compiler complains that:

source_file.cpp: In member function ‘void B<T>::test()’:
source_file.cpp:22:24: error: expected primary-expression before ‘)’ token
         a2.fun< true >();
                        ^

However the line just above (a.fun< true >()) compiles just fine. Interestingly, if I remove the line template< typename T >, then compilation succeeds. However that line is required for reasons that do not appear from the minimal (not) working example. What is wrong here?

Giovanni Mascellani
  • 1,218
  • 2
  • 11
  • 26
  • Possible duplicate of [Where and why do I have to put the "template" and "typename" keywords?](https://stackoverflow.com/questions/610245/where-and-why-do-i-have-to-put-the-template-and-typename-keywords) – Tristan Brindle Oct 25 '17 at 19:06
  • @TristanBrindle I'm not sure of how these cases are handled, but the question is not a duplicate: maybe, in a sense, the answers convey the same information, but the questions are different; OP in the question you link already knows what the "template" keyword is and asks precisations on it; I did not know what it is. – Giovanni Mascellani Oct 25 '17 at 20:29

1 Answers1

2

In this context A2 is actually a shorthand for B<T>::A2. Since A2 is a type dependent on the template parameter T, you have to refer to its member templates with an explicit template keyword

a2.template fun< true >();

A is not a dependent type and its member templates can be referred to with "plain" syntax without that extra template keyword.

See 14.2/4 and a similar example there

14.2 Names of template specializations [temp.names]

4 When the name of a member template specialization appears after . or -> in a postfix-expression or after a nested-name-specifier in a qualified-id, and the object expression of the postfix-expression is type-dependent 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. Otherwise the name is assumed to name a non-template. [ Example:

struct X { 
   template<std::size_t> X* alloc();
   template<std::size_t> static X* adjust();
 };
 template<class T> void f(T* p) {
   T* p1 = p->alloc<200>();          // ill-formed: < means less than
   T* p2 = p->template alloc<200>(); // OK: < starts template argument list
   T::adjust<100>();                 // ill-formed: < means less than
   T::template adjust<100>();        // OK: < starts template argument list
 }

—end example ]

AnT stands with Russia
  • 312,472
  • 42
  • 525
  • 765