Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is no template keyword needed if an unrelated global template function with same name exists?

This question is related to my previous question Compiler error when trying to call template method from private instance, which was pointed out to be related to this question: Where and why do I have to put the "template" and "typename" keywords?

So I read this and I get the idea that the C++ language definition is ambiguous so it cannot always be parsed correctly. In my case, the answer was that I need a.template f<1>() in B::test() to help the parser understand that it is dealing with a template. Fine.

But, after reading all this, why the heck is the parser suddenly able to do without the template keyword if I happen to have a completely unrelated global template function that happens to have the same name? This compiles without problems and behaves as expected:

#include <iostream>

template <int i>
void f() {std::cout << "f()\n";}

template <int N>
struct A {
    template <int i>
    void f() {std::cout << "A::f()\n";}
};

template <int N>
struct B {
    A<N> a;

    B(A<N>& a) : a(a) {}

    void test() {
        f<1>();
        a.f<1>();  // compiles without 'template' keyword!
    }
};

int main() {
    A<2> a;
    a.f<1>();   // works fine
    B<2> b(a);
    b.test();
}

I found that the global function must:

  • be called f
  • be a template function
  • be defined before B

Otherwise, it can be pretty much anything. So

template <typename T, unsigned k>
void *f(double x, const char *s) {return NULL;}

works just as well to help the parser out that a.f<1>() in B::test() is in fact to be parsed as a.template f<1>().

What is the compiler thinking? Like: "Well, the guy already has a global template function called f<>(), so when I'm parsing this completely unrelated expression a.f<1>() inside B::test(), I'm going to assume that it's also a template function?" What is this?

What did I miss when reading Where and why do I have to put the "template" and "typename" keywords??

Update

The code above compiles for me with all of:

  • i686-apple-darwin11-llvm-g++-4.2 (GCC) 4.2.1 (Based on Apple Inc. build 5658) (LLVM build 2336.9.00)
  • Apple clang version 3.1 (tags/Apple/clang-318.0.58) (based on LLVM 3.1svn)
  • g++-4.8 (GCC) 4.8.2

I also tested with the compiler flags -pedantic -Wall -Wextra and with -std=c++11 for g++-4.8. It worked in all cases.

Update 2

This also works without template keyword:

// ...
template <int N, template <int> class A>
struct B {
    A<N> a;

    B(A<N>& a) : a(a) {}

    void test() {
        f<1>();
        a.f<1>();  // compiles without 'template' keyword!
    }
};

int main() {
    A<2> a;
    a.f<1>();   // works fine
    B<2, A> b(a);
    b.test();
}
like image 297
Stefan Avatar asked May 27 '14 14:05

Stefan


People also ask

Which keyword can be used in template?

5. Which keyword is used for the template? Explanation: C++ uses template reserved keyword for defining templates.

What is Typename in C++ template?

" typename " is a keyword in the C++ programming language used when writing templates. It is used for specifying that a dependent name in a template definition or declaration is a type.

What is the task of compiler while handling template?

When you call a function template, the compiler tries to deduce the template type. Most of the time it can do that successfully, but every once in a while you may want to help the compiler deduce the right type — either because it cannot deduce the type at all, or perhaps because it would deduce the wrong type.


1 Answers

I think g++ is correct and the code should compile without .template. According to the standard (at least up to my understanding),

3.4.5/1 (page 55 of N3936)

In a class member access expression (5.2.5), if the . or -> token is immediately followed by an identifier followed by a <, the identifier must be looked up to determine whether the < is the beginning of a template argument list (14.2) or a less-than operator. The identifier is first looked up in the class of the object expression. If the identifier is not found, it is then looked up in the context of the entire postfix-expression and shall name a class template.

like image 118
vsoftco Avatar answered Nov 15 '22 04:11

vsoftco