通过函数签名时 C++ 模板不编译

标签 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 编译得很好?在我看来,只要 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
         ~~~~~~~~~~~~~~~~~~~~~~~~^~~~~

我在这里错过了什么?我正在使用 g++ 7.2.0。

注意:如果这有任何用处,我真的不感兴趣,我只是想知道为什么它不能编译,因为它对我来说毫无意义。

最佳答案

基本上,发生的事情是这样的:

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],

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...)> 不一样),因此退回到默认模板声明,最终产生“使用不完整类型”错误。

关于通过函数签名时 C++ 模板不编译,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46994594/

相关文章:

c++ - C++ 中的继承、范围和模板构造函数

c++ - 可以在模板参数中使用 decltype 吗?

c++ - 脚本库和函数模板

c++ - OpenMesh 无法在最小/最大宏处于事件状态的情况下进行编译

c++ - 通过 C++ 中的模板参数传递类构造函数

c++ - 显示 openGL 后删除文本

c++ - 多线程 C++ 消息传递

c++ - CRTP:将类型从派生类传递到基类

c++ - 在 Qt 中制作关于 GUI 窗口的游戏

c++ - 如何丢弃 QEvent 而不是忽略它