如果在函数模板中声明,是否依赖于本地类? 当前C++编译器(最新的GCC,CLAN)需要下面的例子中的类型名称< /Cord>关键字: template<class T> struct A { }; template<class T> void f(T) { struct C { }; typedef typename A<C>::Type Type; // typename required }
如果在函数模板中声明,是否依赖于本地类? 当前C++编译器(最新的GCC,CLAN)需要下面的例子中的类型名称< /Cord>关键字: template<class T> struct A { }; template<class T> void f(T) { struct C { }; typedef typename A<C>::Type Type; // typename required },c++,templates,language-lawyer,typename,local-class,C++,Templates,Language Lawyer,Typename,Local Class,A现在应该被视为依赖吗?以下是我的推理,希望能有所帮助。本地C在f实例化之前不会实例化。因此,A不是一个实例化,当编译器看到它时,它是不透明的。由于不透明,编译器无法确定A::Type是嵌套类型名还是数据成员或方法。但是,默认情况下,编译器不会将A::Type视为嵌套类型名。因此,需要一个明确的规范。根据我的理解(以及标准的当前措辞),C在您的示例中是不相关的。两者都不是A::Type,因此不需要typename 类模板的嵌套类和函数模板中的本地类之间有一个根本区别:后者不能专门化,因此函数模板
A
现在应该被视为依赖吗?以下是我的推理,希望能有所帮助。本地C
在f
实例化之前不会实例化。因此,A
不是一个实例化,当编译器看到它时,它是不透明的。由于不透明,编译器无法确定A::Type
是嵌套类型名还是数据成员或方法。但是,默认情况下,编译器不会将A::Type
视为嵌套类型名。因此,需要一个明确的规范。根据我的理解(以及标准的当前措辞),C
在您的示例中是不相关的。两者都不是A::Type
,因此不需要typename
类模板的嵌套类和函数模板中的本地类之间有一个根本区别:后者不能专门化,因此函数模板中对本地类的任何引用都是统一的。也就是说,在f
的每个专门化中,C
指在该函数模板f
中定义的类C
。类模板并非如此,因为您确实可以自己显式地专门化成员(如[temp.expl.spec]中所述)
/(1.6)):
模板
A类{C类{};};
模板
类A::C{int i;};
然而:
如果类型是依赖的,则它是依赖的
- 由任何依赖类型构造的复合类型
C
将是依赖的,因为它是根据T
构建的评论部分讨论的标准措辞中存在不一致之处,例如,关于依赖于
T
的成员函数的定义,以及如何将其转换为类依赖关系。标准中似乎没有任何规定此处需要使用typename
关键字。措辞也没有明确说明其他情况,这可能导致GCC在处理f(T)::C
(作为函数模板专业化中的一个本地类)时采取了一些捷径,因为它依赖于T
——扩展而言,这将使a::Type
依赖
没有专门针对这个问题提出,但我认为它提出的附加非规范性文本明确了意图,如果是在标准中,GCC将不要求此处使用
typename
关键字。这似乎与DR 1484有关:他们使用DR页面上的锚,因此,您可以直接提供指向特定缺陷的链接:我认为需要typename
。考虑一些奇怪的例子:我们可以根据模板参数来定义<代码> c>代码>,即使它的名称不是。[TEMP.DEP.Type ] / 8 ->啊,谢谢。所以你漏掉了一些要点。不过,据我所知,这些建议似乎都不适用。在我看来,这似乎是标准中的一个疏忽。这似乎是正确的,但是问题被标记为语言律师,并引用了标准,所以你需要用语言的官方规则来支持你的主张。@BartoszKP你是对的。不管怎样,这里有一些你感兴趣的猜测。编译器生成的错误消息似乎表明,如果嵌套类型的作用域是依赖类型,则即使它本身不是依赖类型,也需要显式的规范。我猜在这种情况下,不管嵌套类型的范围如何,它是否应该实例化都是由实现定义的。我不想讨论这个问题,我只是想鼓励您改进您的答案:)正如您在Columbo的答案中所看到的,声称它是“实现定义的”无论如何都是错误的,模板类中定义的所有嵌套类都是依赖的。在模板结构A{struct B{};void f(){B B;}
,您发现的措辞更改不会使B
不相关。它不能,因为可能会有一个专业化,例如a::B
。但是我认为我现在同意你的观点,本地类可以是非依赖的。你可以专门化A::B
,即使不专门化A
:模板结构A{struct B{int&&m;};void f(){B B;};模板结构A::B{};int main(){A().f();}
完全有效。@hvd Ahh,你是对的。“名称是当前实例化的依赖成员,如果它是当前实例化的成员,并且在查找时引用了作为当前实例化的类的至少一个成员。”我将很快编辑我的答案。我们可以确定本地类是否依赖于该类吗?例如,struct C{auto foo(){return std::conditional::type{};}
@dyp乍一看,C
是不依赖的,但是C::foo
是依赖的。
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
}
template <typename T>
class A { class C{}; };
template <>
class A<int>::C { int i; };