传递函数签名时,C ++模板不编译

时间:2017-10-28 21:19:30

标签: c++ templates

考虑以下最小例子(没有#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编译得很好?在我看来,#3应该等同于其他人,只要foo具有签名void(),它就在这个例子中。即使是编译器告诉我,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
         ~~~~~~~~~~~~~~~~~~~~~~~~^~~~~

我在这里缺少什么?我正在使用g ++ 7.2.0。

注意:如果这对任何方式都有用,我真的不感兴趣,我只想知道为什么它不能编译,因为它对我没用。

1 个答案:

答案 0 :(得分:5)

基本上,这是怎么回事:

Stage2<FuncType>::foobar<func>();

包含一个从属名称(取决于FuncType),因此你必须遵循正确的C ++语法来调用成员模板(因此语法错误消息),这是

Stage2<FuncType>::template foobar<func>();

请注意,这不适用于Stage2<void()>::foobar<func>();,因为不涉及相关名称。

这同样适用于Stage2<decltype(func)>::foobar<func>();,但仅此一点仍无法解决,因为存在一些棘手的障碍。根据§14.1.8[temp.param],

  

“T的数组”或“函数返回T”类型的非类型模板参数分别被调整为“指向T的指针”或“指向函数返回T的指针”。

decltype(func)将是void(*)()而不是void()(即使FuncType指定为void()),因此没有函数类型,但指向函数类型的指针将作为模板参数传递给Stage2,其中没有提供专业化(因为Stage2<Ret (Args...)>Stage2<Ret (*)(Args...)>不相同),因此回退到默认模板声明,最后产生一个“使用不完整类型”错误。