6

以下代码看起来合法但无法编译

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 '>'
}

为什么会出现错误,这是什么意思?

4

1 回答 1

10

当您处理依赖于模板中的模板参数的类型时,编译器不知道该类型的成员是什么类型的东西。除非您另外指定,否则它假定成员不是类型也不是模板。因此,它试图将其<视为小于运算符,但是当表达式到达>.

要摆脱错误,您应该改用它:

call_any<B>::template call<void (&)()>(f);

这明确地告诉编译器这call是一个模板,因此它应该将<视为模板参数的开头,而不是常规的小于运算符。

这也应该使用template

call_any<B>::call<void()>(f); 

您在这一行看不到错误的唯一原因是有一种方法可以将其解析为非模板:

(call_any<B>::call < void() ) > (f);

虽然奇怪,但它在语法上是有效的,所以编译器越过了那行,你看到的第一个错误就是你提到的那个。但是,如果没有template关键字,一旦实际实例化,您最终会得到一个错误call_f(可能 - 它可以以奇怪的方式工作)。

前两个示例可以不使用template关键字。由于类型不依赖于模板参数,因此可以在解析call时确定它是一个模板。call_f

你可能会问:“为什么编译器不能确定它是一个模板?我已经在上面的代码中将它定义为一个模板!”。问题是专业化。您可以专门化模板并执行与主模板指定的完全不同的操作:

template<>
struct call_any<false>
{
    static const int call = 5;
};

即使在定义之后,这种特化也可能发生,因此编译器在解析时call_f不能依赖主模板所说的内容。call_anycall_f

于 2013-07-05T02:04:38.733 回答