在以下示例中:
template<typename T> struct MyList { typedef std::list<T> type1; }; template<typename T> class MyList2 { typename MyList<T>::type1 type2; };
我认为type1和type2都是依赖名,因为它们的类型都依赖于模板参数。但是,为什么第一个被认为是非依赖的,因为我可以使用typedef?
typedef
kg7wmglp1#
在C术语中,依赖名称是语法属性依赖于模板参数的名称。在C中,名称可以表示很多不同的东西,并且可以使用名称的语法位置取决于该名称的某些属性。为了理解X x;试图做什么,编译器需要知道X在程序中的这一点是什么。如果X命名了一个类型,那么这就是声明了一个名为x的变量。编译器不需要知道X的一切,但是从语法上讲,为了理解这段文字,编译器需要知道X在这里命名了一个类型。std::list是类模板的名称;编译器可以很容易地看到,因为这就是它是如何声明的。它不需要声明的主体; template<typename T> class list;就足够了。std::list<T>是一个类模板的示例化,因此仅从声明中,编译器就知道这是一个类型的名称。但是,MyList<T>::type1现在需要的不仅仅是MyList模板的声明。它实际上需要 * 示例化 * 该模板。如果T本身是当前代码的模板参数(就像MyList2的情况一样),那么在最初编译代码时示例化是不可能的。这个示例化必须被延迟,直到MyList2本身被给定一个具体的T来处理。但是编译器仍然必须理解这段代码:typename MyList<T>::type1 type2; .要做到这一点,它需要了解MyList<T>::type1实际上是什么。* 没有 * 示例化MyList<T>。这就是为什么你必须告诉它它是一个typename。
X x;
X
x
std::list
template<typename T> class list;
std::list<T>
MyList<T>::type1
MyList
T
MyList2
typename MyList<T>::type1 type2;
MyList<T>
typename
k2arahey2#
虽然std::list<T>使用T,但它不依赖于T。只要包含<list>,名称std::list就存在。另一方面,typename MyList<T>::type1 type2;确实依赖于T,因为如果不示例化MyList<T>,就无法知道type1是什么。这就是为什么你必须使用typename,因为语法默认情况下会将type1视为成员变量或成员函数,而不是类型。
<list>
type1
2条答案
按热度按时间kg7wmglp1#
在C术语中,依赖名称是语法属性依赖于模板参数的名称。
在C中,名称可以表示很多不同的东西,并且可以使用名称的语法位置取决于该名称的某些属性。为了理解
X x;
试图做什么,编译器需要知道X
在程序中的这一点是什么。如果X
命名了一个类型,那么这就是声明了一个名为x
的变量。编译器不需要知道X
的一切,但是从语法上讲,为了理解这段文字,编译器需要知道X
在这里命名了一个类型。std::list
是类模板的名称;编译器可以很容易地看到,因为这就是它是如何声明的。它不需要声明的主体;template<typename T> class list;
就足够了。std::list<T>
是一个类模板的示例化,因此仅从声明中,编译器就知道这是一个类型的名称。但是,
MyList<T>::type1
现在需要的不仅仅是MyList
模板的声明。它实际上需要 * 示例化 * 该模板。如果T
本身是当前代码的模板参数(就像MyList2
的情况一样),那么在最初编译代码时示例化是不可能的。这个示例化必须被延迟,直到MyList2
本身被给定一个具体的T
来处理。但是编译器仍然必须理解这段代码:
typename MyList<T>::type1 type2;
.要做到这一点,它需要了解MyList<T>::type1
实际上是什么。* 没有 * 示例化MyList<T>
。这就是为什么你必须告诉它它是一个
typename
。k2arahey2#
虽然
std::list<T>
使用T
,但它不依赖于T
。只要包含<list>
,名称std::list
就存在。另一方面,
typename MyList<T>::type1 type2;
确实依赖于T
,因为如果不示例化MyList<T>
,就无法知道type1
是什么。这就是为什么你必须使用typename
,因为语法默认情况下会将type1
视为成员变量或成员函数,而不是类型。