C++ 正式地说,typename 是做什么用的?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1600936/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Officially, what is typename for?
提问by dicroce
On occasion I've seen some really indecipherable error messages spit out by gcc
when using templates... Specifically, I've had problems where seemingly correct declarations were causing very strange compile errors that magically went away by prefixing the typename
keyword to the beginning of the declaration... (For example, just last week, I was declaring two iterators as members of another templated class and I had to do this)...
有时我会看到gcc
使用模板时会吐出一些非常难以理解的错误消息......具体来说,我遇到过看似正确的声明导致非常奇怪的编译错误的问题,这些错误通过将typename
关键字添加到开头而神奇地消失了声明...(例如,就在上周,我将两个迭代器声明为另一个模板化类的成员,我不得不这样做)...
What's the story on typename
?
讲的是什么故事typename
?
回答by Naveen
Following is the quote from Josuttis book:
以下是 Josuttis 书中的引述:
The keyword
typename
was introduced to specify that the identifier that follows is a type. Consider the following example:template <class T> Class MyClass { typename T::SubType * ptr; ... };
Here,
typename
is used to clarify thatSubType
is a type ofclass T
. Thus,ptr
is a pointer to the typeT::SubType
. Withouttypename
,SubType
would be considered a static member. ThusT::SubType * ptr
would be a multiplication of value
SubType
of typeT
withptr
.
typename
引入关键字是为了指定后面的标识符是一种类型。考虑以下示例:template <class T> Class MyClass { typename T::SubType * ptr; ... };
在这里,
typename
用于说明它SubType
是class T
. 因此,ptr
是一个指向类型的指针T::SubType
。没有typename
,SubType
将被视为静态成员。因此T::SubType * ptr
将是
SubType
类型值T
与的乘积ptr
。
回答by Xinus
Stan Lippman's BLog postsuggests :-
Stroustrup reused the existing class keywordto specify a type parameter rather than introduce a new keyword that might of course break existing programs. It wasn't that a new keyword wasn't considered -- just that it wasn't considered necessary given its potential disruption. And up until the ISO-C++ standard, this was the only way to declare a type parameter.
Stroustrup重用了现有的 class 关键字来指定类型参数,而不是引入一个新关键字,这当然可能会破坏现有程序。并不是没有考虑新关键字——只是考虑到它的潜在破坏性,它被认为没有必要。而直到ISO-C ++标准,这是声明的类型参数的唯一途径。
So basically Stroustrup reused class keyword without introducing a new keyword which is changed afterwards in the standard for the following reasons
所以基本上 Stroustrup 重用了 class 关键字而不引入新的关键字,由于以下原因,该关键字后来在标准中发生了变化
As the example given
正如给出的例子
template <class T>
class Demonstration {
public:
void method() {
T::A *aObj; // oops …
// …
};
language grammar misinterprets T::A *aObj;
as an arithmetic expression so a new keyword is introduced called typename
语言语法错误地解释T::A *aObj;
为算术表达式,因此引入了一个新关键字,称为typename
typename T::A* a6;
it instructs the compiler to treat the subsequent statement as a declaration.
它指示编译器将后续语句视为声明。
Since the keyword was on the payroll, heck, why not fix the confusion caused by the original decisionto reuse the class keyword.
既然关键字在工资单上,见鬼,为什么不解决由重用 class 关键字的原始决定引起的混乱。
Thats why we have both
这就是为什么我们有两个
You can have a look at this post, it will definitely help you, I just extracted from it as much as I could
你可以看看这篇文章,它肯定会对你有帮助,我只是尽可能多地从中提取
回答by moonshadow
Consider the code
考虑代码
template<class T> somefunction( T * arg )
{
T::sometype x; // broken
.
.
Unfortunately, the compiler is not required to be psychic, and doesn't know whether T::sometype will end up referring to a type name or a static member of T. So, one uses typename
to tell it:
不幸的是,编译器不需要通灵,并且不知道 T::sometype 最终是否会引用类型名称或 T 的静态成员。 所以,有人typename
用来告诉它:
template<class T> somefunction( T * arg )
{
typename T::sometype x; // works!
.
.
回答by AnT
In some situations where you refer to a member of so called dependenttype (meaning "dependent on template parameter"), the compiler cannot always unambiguously deduce the semantic meaning of the resultant construct, because it doesn't know what kind of name that is (i.e. whether it is a name of a type, a name of a data member or name of something else). In cases like that you have to disambiguate the situation by explicitly telling the compiler that the name belongs to a typename defined as a member of that dependent type.
在某些情况下,您引用所谓的依赖类型的成员(意思是“依赖模板参数”),编译器不能总是明确地推断出结果构造的语义,因为它不知道是什么类型的名称(即无论是类型名称、数据成员名称还是其他名称)。在这种情况下,您必须通过显式告诉编译器该名称属于定义为该依赖类型成员的 typename 来消除这种情况的歧义。
For example
例如
template <class T> struct S {
typename T::type i;
};
In this example the keyword typename
in necessary for the code to compile.
在这个例子中,关键字typename
是编译代码所必需的。
The same thing happens when you want to refer to a template member of dependent type, i.e. to a name that designates a template. You also have to help the compiler by using the keyword template
, although it is placed differently
当您想要引用依赖类型的模板成员时,也会发生同样的事情,即指定模板的名称。您还必须使用关键字来帮助编译器template
,尽管它的位置不同
template <class T> struct S {
T::template ptr<int> p;
};
In some cases it might be necessary to use both
在某些情况下,可能需要同时使用
template <class T> struct S {
typename T::template ptr<int>::type i;
};
(if I got the syntax correctly).
(如果我的语法正确)。
Of course, another role of the keyword typename
is to be used in template parameter declarations.
当然,关键字的另一个作用typename
是用于模板参数声明。
回答by phlipsy
The secret lies in the fact that a template can be specialized for some types. This means it also can define the interface completely different for several types. For example you can write:
秘密在于模板可以专门用于某些类型。这意味着它还可以为几种类型定义完全不同的接口。例如你可以写:
template<typename T>
struct test {
typedef T* ptr;
};
template<> // complete specialization
struct test<int> { // for the case T is int
T* ptr;
};
One might ask why is this useful and indeed: That really looks useless. But take in mind that for example std::vector<bool>
the reference
type looks completely different than for other T
s. Admittedly it doesn't change the kind of reference
from a type to something different but nevertheless it could happen.
有人可能会问为什么这很有用,事实上:这看起来真的没用。不过,要记住,例如std::vector<bool>
该reference
类型看起来比其他完全不同T
秒。不可否认,它不会将类型reference
从类型更改为不同的类型,但它仍然可能发生。
Now what happens if you write your own templates using this test
template. Something like this
现在,如果您使用此test
模板编写自己的模板会发生什么。像这样的东西
template<typename T>
void print(T& x) {
test<T>::ptr p = &x;
std::cout << *p << std::endl;
}
it seems to be ok for you because you expectthat test<T>::ptr
is a type. But the compiler doesn't know and in deed he is even advised by the standard to expect the opposite, test<T>::ptr
isn't a type. To tell the compiler what you expect you have to add a typename
before. The correct template looks like this
对您来说似乎没问题,因为您希望这test<T>::ptr
是一种类型。但是编译器不知道,事实上,标准甚至建议他期望相反,test<T>::ptr
它不是一种类型。要告诉编译器您期望什么,您必须在typename
之前添加一个。正确的模板如下所示
template<typename T>
void print(T& x) {
typename test<T>::ptr p = &x;
std::cout << *p << std::endl;
}
Bottom line: You have to add typename
before whenever you use a nested type of a template in your templates. (Of course only if a template parameter of your template is used for that inner template.)
底线:typename
每当您在模板中使用嵌套类型的模板时,您都必须添加before。(当然,仅当您的模板的模板参数用于该内部模板时。)
回答by Gupta
I think all of the answers have mentioned that the typename
keyword, is used in two different cases:
我认为所有答案都提到了typename
关键字,用于两种不同的情况:
a) When declaring a template type parameter. e.g.
a) 声明模板类型参数时。例如
template<class T> class MyClass{}; // these two cases are
template<typename T> class MyNewClass{}; // exactly the same.
Which there is no difference between them and they are EXACTLY the same.
它们之间没有区别,它们完全相同。
b) Before using a nested dependent type namefor a template.
b) 在为模板使用嵌套依赖类型名称之前。
template<class T>
void foo(const T & param)
{
typename T::NestedType * value; // we should use typename here
}
Which not using typename
leads to parsing/compilation errors.
哪个不使用typename
会导致解析/编译错误。
What I want to add to the second case, as mentioned in Scot Meyers book Effective C++, is that there is an exception of using typename
before a nested dependant type name. The exception is that if you use the nested dependant type nameeither as a base classor in a member initialization list, you should not use typename
there:
正如 Scot Meyers 的书Effective C++ 中提到的,我想对第二种情况添加的是,typename
在嵌套依赖类型 name之前使用 using 是一个例外。例外情况是,如果您将嵌套的依赖类型名称用作基类或成员初始化列表,则不应typename
在那里使用:
template<class T>
class D : public B<T>::NestedType // No need for typename here
{
public:
D(std::string str) : B<T>::NestedType(str) // No need for typename here
{
typename B<T>::AnotherNestedType * x; // typename is needed here
}
}
Note:Using typename
for the second case (i.e. before nested dependent type name) is not needed since C++20.
注意:使用typename
用于所述第二情况下(即前嵌套依赖型名称)不因为C ++ 20需要的。
回答by Phillip Ngan
Two uses:
两种用途:
- As a
template
argument keyword (instead ofclass
) - A
typename
keyword tells the compiler that an identifier is a type (rather than a static member variable)
- 作为
template
参数关键字(而不是class
) - 甲
typename
关键字告诉编译器的标识符是一种类型的(而不是静态成员变量)
template <typename T> class X // [1] { typename T::Y _member; // [2] }
template <typename T> class X // [1] { typename T::Y _member; // [2] }
回答by Jobin
#include <iostream>
class A {
public:
typedef int my_t;
};
template <class T>
class B {
public:
// T::my_t *ptr; // It will produce compilation error
typename T::my_t *ptr; // It will output 5
};
int main() {
B<A> b;
int my_int = 5;
b.ptr = &my_int;
std::cout << *b.ptr;
std::cin.ignore();
return 0;
}