2013-07-05 200 views
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 '>' 
} 

为什么有错误,这是什么意思的模板方法?

回答

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_any主模板时说:它解析call_f

相关问题