4 回答
TA贡献1942条经验 获得超3个赞
是什么目的typename
和template
?
typename
并且template
可以在声明模板以外的情况下使用。
在C ++中有某些上下文,其中必须明确地告诉编译器如何处理名称,并且所有这些上下文都有一个共同点; 它们依赖于至少一个模板参数。
我们指的是这样的名称,在解释中可能存在歧义,因为; “ 从属名称 ”。
这篇文章将解释依赖名称和两个关键字之间的关系。
一个SNACKET超过1000字
尝试解释以下功能模板中发生的事情,无论是对自己,朋友,还是你的猫; 标记为(A)的声明中发生了什么?
template<class T> void f_tmpl () { T::foo * x; /* <-- (A) */ }
它可能不像人们想象的那么容易,更具体地说,评估(A)的结果在很大程度上取决于作为模板参数传递的类型的定义T
。
不同的T
s可以彻底改变所涉及的语义。
struct X { typedef int foo; }; /* (C) --> */ f_tmpl<X> ();struct Y { static int const foo = 123; }; /* (D) --> */ f_tmpl<Y> ();
两种不同的场景:
如果我们用类型X实例化函数模板,就像在(C)中一样,我们将声明一个名为x的指向int的指针,但是;
如果我们用类型Y实例化模板,如(D)中所示,(A)将由一个表达式组成,该表达式计算123的乘积乘以一些已经声明的变量x。
理由
C ++标准关心我们的安全和幸福,至少在这种情况下。
为了防止实现可能遭受令人讨厌的意外,标准要求我们通过明确说明我们想要将名称视为类型名称或模板的任何地方来明确依赖名称的歧义。id。
如果没有说明,则依赖名称将被视为变量或函数。
如何处理依赖名称?
如果这是一部好莱坞电影,依赖名字将是通过身体接触传播的疾病,立即影响其主人,使其混淆。混乱可能会导致一个形成不良的人,erhm ..计划。
甲从属名称是任何名称直接或间接依赖于模板的参数。
template<class T> void g_tmpl () { SomeTrait<T>::type foo; // (E), ill-formed SomeTrait<T>::NestedTrait<int>::type bar; // (F), ill-formed foo.data<int> (); // (G), ill-formed }
我们在上面的代码段中有四个依赖名称:
E)
“类型”取决于实例化
SomeTrait<T>
,包括T
和;F)
“NestedTrait”,它是一个模板ID,取决于
SomeTrait<T>
,和;(F)末尾的“type”取决于NestedTrait,它取决于
SomeTrait<T>
,和;G)
“data”看起来像一个成员函数模板,间接是一个依赖名称,因为foo的类型取决于它的实例化
SomeTrait<T>
。
如果编译器将依赖名称解释为变量/函数(如前所述,如果我们没有明确说明,则会发生的情况),语句(E),(F)或(G)都不是有效的。
解决方案
为了使g_tmpl
有一个有效的定义,我们必须明确告诉编译器我们期望(E)中的类型,(F)中的模板ID和类型,以及(G)中的模板ID。
template<class T> void g_tmpl () { typename SomeTrait<T>::type foo; // (G), legal typename SomeTrait<T>::template NestedTrait<int>::type bar; // (H), legal foo.template data<int> (); // (I), legal}
每次名称表示一个类型时,所 涉及的所有名称都必须是类型名称或名称空间,考虑到这一点,我们很容易看到我们typename
在完全限定名称的开头应用。
template
但是,在这方面是不同的,因为没有办法得出如下结论; “哦,这是一个模板,那么另外一件事也必须是模板”。这意味着我们template
直接在我们想要处理的任何名称前面申请。
我是否只能在任何名字的前面贴上关键词?
“ 我可以坚持
typename
并template
在任何名字前面吗?我不想担心它们出现的背景...... ” -Some C++ Developer
标准中的规则规定,只要您处理限定名称(K),就可以应用关键字,但如果名称不合格,则应用程序格式错误(L)。
namespace N { template<class T> struct X { };}
N:: X<int> a; // ... legaltypename N::template X<int> b; // (K), legaltypename template X<int> c; // (L), ill-formed
注意:申请typename
或template
在不需要的情况下,不被视为良好做法; 仅仅因为你可以做某事,并不意味着你应该做。
此外,还有地方环境typename
和template
被明确禁止:
指定类继承的基础时
在派生类的base-specifier-list中编写的每个名称都已被视为类型名称,显式指定
typename
既是格式错误又是冗余。// .------- the base-specifier-list template<class T> // v struct Derived : typename SomeTrait<T>::type /* <- ill-formed */ { ... };
当template-id是派生类的using-directive中引用的那个时
struct Base { template<class T> struct type { }; }; struct Derived : Base { using Base::template type; // ill-formed using Base::type; // legal };
- 4 回答
- 0 关注
- 768 浏览
添加回答
举报