【问题标题】:Why is this declaration of a function in template class invalid?为什么模板类中的函数声明无效?
【发布时间】:2015-11-26 18:03:24
【问题描述】:

考虑以下代码:

template<int X, int Y>
struct S
{
    typedef int func(int,float) const;
};

template<int X>
struct D : public S<X,6>
{
    typename S<X,6>::func func;
};
template<int X>
int D<X>::func(int,float) const
{
    return 1;
}
//----------------
struct W : public S<7,8>
{
    S<7,8>::func func;
};
int W::func(int,float) const
{
    return 2;
}

#include <iostream>
int main()
{
    W w;
    std::cout << w.func(1,4.3) << "\n";
    D<3> d;
    std::cout << d.func(1,4.3) << "\n";
}

如果我注释掉声明类DD::func() 的代码以及main() 中的相应行,则代码编译正常,并且我在输出中看到2,正如预期的那样。

但是当我制作派生类模板时(在函数声明之前添加typename,因为S&lt;X.6&gt;是一个依赖范围),我得到以下错误:

test.cpp:13:27: error: no ‘int D<X>::func(int, float) const’ member function declared in class ‘D<X>’
 int D<X>::func(int,float) const
                           ^
test.cpp: In instantiation of ‘struct D<3>’:
test.cpp:32:10:   required from here
test.cpp:10:27: error: field ‘D<3>::func’ invalidly declared function type
     typename S<X,6>::func func;
                           ^
  • 为什么我不能在模板派生类中声明func,而在非模板类中却可以?
  • 究竟什么是“无效声明的函数类型”?这里什么无效?

【问题讨论】:

  • 我感觉这在规范中的 [dcl.fct]/10 在技术上是有效的,但是声明一个具有依赖 typedef 的函数就像是极端情况的极端情况:我是不确定是否有任何编译器会像你期望的那样处理它。
  • 我会说S&lt;X,6&gt;可能是后者,所以D&lt;X&gt;::func的定义可能会失效。
  • @Jarod42 看起来我们需要function_typename 以及typename :p
  • 请注意,在D 中使用typename S&lt;7,6&gt;::func func; 有效(Demo)。
  • @Jarod42 这并不奇怪,因为它与W 中的大部分内容相同。在这种情况下,您甚至不需要 typename,因为 S&lt;7,6&gt; 不是依赖范围。

标签: c++ templates methods types


【解决方案1】:

N3337 [dcl.fct]/10:typedef 函数类型可用于声明函数,但不得用于定义函数。

根据这条规则,DW 在技术上都是正确的。我认为这不能用 GCC 或 Clang 编译的原因是用 typedef 声明一个函数真的很少见。使用依赖于模板参数的成员 typedef 声明一个函数更加罕见。看起来您刚刚遇到了编译器支持有限的黑暗角落。

有趣的是,MSVC 居然在这里does the right thing

您最好的选择可能是找到一种不同的方式来表达您的课程。如果不了解您要解决的问题的更多信息,我真的无法提供任何直接的建议,但如果您提出一个新的详细问题,我们可以提供一些建议。

您可能还考虑为GCCClang 提交错误报告。


编辑:

但是,正如 Jarod42 所指出的,依赖类型稍后可能被定义为函数类型以外的东西,从而使声明无效。 MSVC 在 GCC 和 Clang 不适用的地方工作的原因与 MSVC 在某些地方不需要 typename 的原因相同:它没有正确实现两阶段查找。完全指定这种情况需要function_typename 之类的东西来将依赖名称标记为函数类型。我认为基于依赖类型声明函数的定义不足且不一致,因为这是一种非常罕见的情况。

【讨论】:

  • 即使function_typename 也不够,签名可能与定义不同(或需要新定义才能进行专业化)。
  • @Jarod42 没错,它需要明确声明 typedef 所代表的签名,这首先完全破坏了这样做的全部意义。
  • 为什么这是一个问题,专业化会使声明无效?是否有任何假设声明是有效的,在某个时间点之后不能被打破?
【解决方案2】:

正如错误消息所述:D func 不是成员函数,因此您无法为其提供定义。它是一个类型为S&lt;X,6&gt;::func 的成员。

【讨论】:

    猜你喜欢
    • 2011-08-27
    • 1970-01-01
    • 1970-01-01
    • 2013-09-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多