考虑以下最小的例子(没有#1和#2编译):
void foo(void) { } template<typename T> class Stage2; template<typename Ret,typename... Args> struct Stage2<Ret (Args...)> { template<Ret (*func)(Args...)> static void foobar(void) { /* Do something */ } }; template<typename FuncType> struct Stage1 { template<FuncType func> static void bar(void) { Stage2<FuncType>::foobar<func>(); // #1,Not working Stage2<decltype(func)>::foobar<func>(); // #2,Not working Stage2<void()>::foobar<func>(); // #3,Working } }; int main(void) { Stage1<decltype(foo)>::bar<foo>(); return 0; }
为什么它不能用#1和#2编译,而它用#3编译得很好?在我看来,只要foo具有签名void(),#3就应该等同于其他的,在本例中它就是这样.即使编译器告诉我,FuncType实际上也是void()(见下文).
错误消息(#1和#2相同):
main.cpp: In static member function ‘static void Stage1<FuncType>::bar()’: main.cpp:21:40: error: expected primary-expression before ‘)’ token Stage2<FuncType>::foobar<func>(); // #1,Not working ^ main.cpp: In instantiation of ‘static void Stage1<FuncType>::bar() [with FuncType func = foo; FuncType = void()]’: main.cpp:29:37: required from here main.cpp:21:33: error: invalid operands of types ‘<unresolved overloaded function type>’ and ‘void (*)()’ to binary ‘operator<’ Stage2<FuncType>::foobar<func>(); // #1,Not working ~~~~~~~~~~~~~~~~~~~~~~~~^~~~~
我在这里想念的是什么?我用的是7.2.0.
注意:如果这对任何方式都有用,我真的不感兴趣,我只想知道它为什么不编译,因为它对我没用.
解决方法
基本上,这是怎么回事:
Stage2<FuncType>::foobar<func>();
包含一个从属名称(取决于FuncType),因此您必须遵循正确的C -Syntax来调用成员模板(因此语法错误消息),这是
Stage2<FuncType>::template foobar<func>();
请注意,这不适用于Stage2< void()> :: foobar< func>();因为没有涉及的附属名称.
这同样适用于Stage2< decltype(func)> :: foobar< func>();,但是这仍然无法修复它,因为存在一些棘手的障碍.根据§14.1.8[temp.param],
A non-type template-parameter of type “array of T” or “function returning T” is adjusted to be of type “pointer to T” or “pointer to function returning T”,respectively.
decltype(func)将为void(*)()而不是void()(即使FuncType被指定为void()),因此没有函数类型,但指向函数类型的指针将作为模板参数传递给Stage2,没有提供专业化(因为Stage2< Ret(Args ...)>和Stage2< Ret(*)(Args ...)>不一样),因此回退到默认模板声明,最后产生一个“使用不完整类型”错误.