是否依赖于本地类(如果在函数模板中声明)

Is a local class dependent if declared within a function template?

本文关键字:函数模板 声明 如果 依赖于 是否      更新时间:2023-10-16

当前C++编译器(最新的gcc,clang)在下面的示例中需要typename关键字:

template<class T>
struct A
{
};
template<class T>
void f(T)
{
    struct C
    {
    };
    typedef typename A<C>::Type Type; // typename required
}

如果省略typename gcc (4.9, 5.0) 将报告错误:

need 'typename' before 'A<f(T)::C>::Type' because 'A<f(T)::C>' is a dependent scope

根据我对 C++11 标准的解读,此示例的格式良好。

以下措辞似乎涵盖了这种行为:

[温度类型]/8

如果类型是

  • 模板参数,

  • 未知专业的成员,

  • 作为当前实例化成员的嵌套类或枚举,

  • 符合 CV 条件的类型,
  • 其中 CV 不合格类型是相关的,

  • 由任何依赖类型构造的复合类型,

  • 从任何依赖类型构造的数组类型,或者其大小由常量表达式指定 这是值依赖的,

  • 简单模板 ID,其中模板名称是模板参数或任何模板 参数是依赖类型或依赖于类型或值的表达式,或者

  • 由 decltype(expression) 表示,其中表达式与类型相关。

但是,根据 [class.local] 的说法,类C本地类而不是嵌套类。如果是这样,为什么要将A<C>视为受抚养人?

编辑

对于奖励积分,如果通过将成员枚举添加到C来修改示例,如下所示:

template<typename T>
struct A
{
    typedef T Type;
};
template<class T>
void f(T)
{
    struct C
    {
        enum { value = T::value };
    };
    typedef typename A<C>::Type Type; // typename required
}

A<C>现在应该被视为受抚养人吗?

根据我的理解(以及标准的当前措辞),您示例中的C不依赖于。两者都不是A<C>::Type,所以typename不是必需的。

类模板的嵌套类和函数模板中的本地类

之间存在根本区别:后者不能专用化,因此对函数模板中本地类的任何引用都是统一的。也就是说,在f的每个专用化中,C 是指在此函数模板f中定义的类C。类模板不是这种情况,因为您确实可以显式地将成员专用化(如 [temp.expl.spec] 中所述)/(1.6)):

template <typename T>
class A { class C{}; };
template <>
class A<int>::C { int i; };

然而:

如果类型是

  • 由任何依赖类型构造的复合类型,

因此,如果定义是按照 dyp 的示例完成的,C 将是依赖的,因为它是由 T 构造的。
评论部分正在讨论的标准措辞中存在不明确之处,例如,关于依赖于T的成员函数的定义以及如何将其转换为类依赖项。

以下是我的推理,希望对您有所帮助。本地Cf实例化之前不会实例化。因此,A<C>不是实例化,并且在编译器看到它时对它不透明。由于不透明性,编译器无法确定A<C>::Type是嵌套类型名称、数据成员还是方法。但是,默认情况下,编译器不会将A<C>::Type视为嵌套类型名称。因此,需要一个明确的规范。

标准中似乎没有任何内容表明 typename 关键字在这里应该是必需的。该措辞也没有明确说明其他内容,这可能导致GCC在将f<T>(T)::C(作为函数模板专用化中的本地类)视为依赖于T方面采取了一些捷径 - 通过扩展,这将使A<[f<T>(T)::]C>::Type依赖。

核心缺陷 1484 没有专门针对这个问题提出,但我认为它提出的附加非规范性文本明确了意图,如果它在标准中,GCC 将合规地不需要这里的 typename 关键字。