为什么在尝试使用显式类型参数调用模板成员函数时出现错误?


71

我不明白,在我看来呼叫f完全明确,但无法使用进行编译expected primary-expression before ‘int’。如果我将对的调用f注释掉,则可以正常编译。

template<typename T>
struct A {
    template<typename S>
    void f() { }
};

template<typename T>
struct B : A<T> {
    void g() {
        this->f<int>();
    }
};

29
我赞扬您不仅发现了这个邪恶的问题,而且在描述它时从未发誓过。

Answers:


134

这是由于该标准的一个晦涩难懂的规定,在该规定中,如果您有一个模板试图在其类型取决于模板参数的对象中访问模板函数,则必须以template一种奇怪的方式使用关键字:

this->template f<int>();

这类似于typename依赖类型带来的怪异,除了应用于函数。特别是,如果您省略了template关键字,则之间存在解析歧义

this->f<int>()

(您的意图),以及

((this->f) < int) > ()

这没有任何意义(因此会导致您的错误)。关键字的使用template消除歧义,并迫使编译器认识到它正在寻找对模板成员函数的完全有效的调用,而不是大量乱码。

希望这可以帮助!


2
我已经知道模板有一些语法怪异之处,但是我以前从未听过。
Gorpik

70
不仅答案是好的,而且它还有一个名为templatetypedef的用户所提供的额外好处:-)他肯定知道他在说什么...
Francesco

3
Visual Studio在某些模板功能上有点松懈。例如,它可以让您在技术上需要的某些情况下忽略typename,并自动从不应有的模板库中导入名称。如果这是C ++ 0x,而不仅仅是VS中的怪癖,我会感到惊讶。
templatetypedef

2
@Pedro:否,Visual C ++不兼容,因为它仅在实例化时检查模板,而不是两阶段查找。
Matthieu M.

3
@James:您无法早期诊断出明显的错误(缺少,键入;错误等),并且在重载解析中一团糟(通常只考虑在模板之前声明的函数,但是使用此VC ++,您可以将后来声明的函数考虑在内,模板的编写者可能没有想到这些函数)...我想肯定它不能更好地工作。但是,对于编译器发出这样的愚蠢警告是很愚蠢的(与类型进行比较是没有意义的...),但是gcc从未因其用户友好性而闻名:/
Matthieu M.11年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.