以下代码看起来合法但不编译
void f() {}
template<bool>
struct call_any
{
template<typename F>
static void call(F f) {}
};
template<bool B>
void call_f()
{
call_any<true>::call<void (&)()>(f); // OK
call_any<false>::call<void (&)()>(f); // OK
call_any<B>::call<void()>(f); // OK
call_any<B>::call<void (&)()>(f); // expected primary-expression before '>'
}
Run Code Online (Sandbox Code Playgroud)
为什么会出现错误,这是什么意思?
Vau*_*ato 10
当您处理依赖于模板中的模板参数的类型时,编译器不知道该类型的成员是什么类型的事物.除非您另行指定,否则它假定成员不是类型而不是模板.因此,它试图将其<视为一个小于运算符,但是当它到达时,就不可能解析表达式>.
要摆脱错误,你应该使用它:
call_any<B>::template call<void (&)()>(f);
Run Code Online (Sandbox Code Playgroud)
这会明确告诉编译器这call是一个模板,因此它应该将其<视为模板参数的开头而不是常规的小于运算符.
这也应该使用template:
call_any<B>::call<void()>(f);
Run Code Online (Sandbox Code Playgroud)
您没有在此行上看到错误的唯一原因是有一种方法可以将其解析为非模板:
(call_any<B>::call < void() ) > (f);
Run Code Online (Sandbox Code Playgroud)
虽然很奇怪,但它在语法上是有效的,所以编译器会越过那一行,你看到的第一个错误是你提到的错误.但是,如果没有template关键字,一旦call_f实际实例化,你最终会得到一个错误(可能 - 它有可能工作的奇怪方式).
前两个例子可以不使用template关键字.由于类型不依赖于模板参数,因此可以确定在解析call时它是模板call_f.
您可能会问:"为什么编译器无法确定它是模板?我已将其定义为上面代码中的模板!".问题是专业化.您可以专门化模板并执行与主模板指定的完全不同的操作:
template<>
struct call_any<false>
{
static const int call = 5;
};
Run Code Online (Sandbox Code Playgroud)
即使在call_f定义之后,这种特化也可能发生,因此编译器在call_any解析时不能依赖主模板所说的内容call_f.