如果存在具有相同名称的不相关全局模板函数,为什么不需要模板关键字?

时间:2014-05-27 14:47:24

标签: c++ templates compiler-errors

此问题与我之前提出的问题Compiler error when trying to call template method from private instance有关,该问题被指出与此问题有关:Where and why do I have to put the "template" and "typename" keywords?

所以我读了这篇文章,并且我认为C ++语言定义含糊不清,所以不能总是正确解析它。就我而言,答案是我需要a.template f<1>()中的B::test()来帮助解析器理解它正在处理模板。细

但是,在阅读了所有这些之后,如果碰巧有一个完全不相关的全局模板函数碰巧具有相同的名称,为什么解析器突然能够在没有template关键字的情况下完成?这可以毫无问题地编译并且按预期运行:

#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();
}

我发现全局函数必须:

  • 被称为f
  • 是模板功能
  • B
  • 之前定义

否则,它几乎可以是任何东西。所以

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

也可以帮助解析器,a.f<1>()中的B::test()实际上被解析为a.template f<1>()

编译器在想什么?喜欢:“嗯,这家伙已经有一个名为f<>()的全局模板函数,所以当我在a.f<1>()内解析这个完全不相关的表达式B::test()时,我会假设它是还有模板功能吗?“这是什么?

阅读Where and why do I have to put the "template" and "typename" keywords?时我错过了什么?

更新

上面的代码为我编译所有:

  • i686-apple-darwin11-llvm-g ++ - 4.2(GCC)4.2.1(基于Apple Inc. build 5658)(LLVM build 2336.9.00)
  • Apple clang 3.1版(标签/ Apple / clang-318.0.58)(基于LLVM 3.1svn)
  • g ++ - 4.8(GCC)4.8.2

我还使用编译器标志-pedantic -Wall -Wextra-std=c++11测试g++-4.8。它适用于所有情况。

更新2

这也可以在没有template关键字的情况下使用:

// ...
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();
}

1 个答案:

答案 0 :(得分:2)

我认为g++是正确的,代码应该在没有.template的情况下编译。根据标准(至少根据我的理解),

3.4.5 / 1 (N3936第55页)

在类成员访问表达式(5.2.5)中,如果是。或 - &gt;令牌后面紧跟着一个标识符,后跟一个&lt ;,必须查找标识符以确定&lt;是模板参数列表(14.2)或小于运算符的开头。首先在对象表达式的类中查找标识符。如果找不到标识符,则在整个postfix-expression的上下文中查找它,并命名一个类模板。