为什么这段代码不能编译?
struct A {
template <class T>
static T a(int i) { return 2*i; }
};
template <class T>
struct B {
double b;
B(): b(T::a<double>(5)) {}
};
template class B<A>;
编译器甚至没有到达模板实例化。我正在使用gcc 4.7.0。
test.cc: In constructor »B<T>::B()«:
test.cc:9:25: Error: expected »(« before »<« token
test.cc:9:26: Error: expected primary-expression before »double«
答案 0 :(得分:6)
您错过了template
个关键字,因为a
是一个从属名称(或类似名称)。
B(): b(T::template a<double>(5)) {}
(您的最后一行也应为template struct B<A>;
。)
有关血淋淋的细节,请参阅: Where and why do I have to put the "template" and "typename" keywords?
答案 1 :(得分:2)
您必须在方法名称前添加template
:
B(): b(T::template a<double>(5)) {}
这是因为在解析模板类B
时,编译器不知道T::a
是模板化方法(因为在此之前未指定T
,并且{{ 1}}完全未知),因此它不知道T::a
应该被解析为模板参数列表。
它也可能意味着并且确实将被解析为:<double>
小于T::a
大于double
。当然,(0)
不是表达,所以这很脆弱;因此错误信息。所以编译器可能只是假设你希望它是一个模板化的函数调用。但是你也可以有一个非类型的模板参数,例如一个int,所以double
可以解析为T::a<42>(5)
小于T::a
大于42
,不是模板。但您希望将其解析为(5)
,然后将参数T::a
解析为模板参数列表,然后使用参数42
解析调用操作符。
要告诉编译器它是一个模板化的函数调用,你必须在函数名之前加上5
。
答案 2 :(得分:0)
编译器对T一无所知。所以每次你编写T::{something}
它都假设{something}
是成员变量或T的方法。如果不是,你必须告诉它它是什么是。如果您所指的是类型而不是变量,您可能知道必须使用的typename
关键字。模板成员也有类似的技巧:
template <class T>
struct B {
double b;
B(): b(T::template a<double>(5)) {}
};
现在编译器知道a
是一个模板,之后的是模板参数列表。