将函数作为参数传递给模板类的模板方法

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

为什么会出现错误,这个错误的含义是什么?
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_f时,call是一个模板。
您可能会问:“为什么编译器无法弄清它是一个模板? 我在代码中刚刚定义了它作为模板!”。问题在于特化。您可以专门针对模板执行某些与主要模板指定完全不同的操作:
template<>
struct call_any<false>
{
    static const int call = 5;
};

即使在定义call_f之后也可能发生这种特化,因此编译器在解析call_f时不能依赖于call_any的主模板说了什么。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接