这个问题在这里已有答案:
我正在阅读C代码,我在类定义的中间遇到了关键字 typename
的使用 .
这是类定义,关键字在受保护的部分中使用 .
template<typename CVertex, typename CEdge, typename CFace, typename CHalfEdge>
class CBoundary
{
typedef CLoop<CVertex,CEdge, CFace, CHalfEdge> TLoop;
public:
CBoundary( CBaseMesh<CVertex,CEdge,CFace,CHalfEdge> * pMesh );
~CBoundary();
std::vector<TLoop*> & loops()
{
return m_loops;
}
protected:
CBaseMesh<CVertex,CEdge,CFace,CHalfEdge> * m_pMesh;
typename std::vector<TLoop*> m_loops;
void _bubble_sort( std::vector<CLoop<CVertex, CEdge, CFace, CHalfEdge>*> & loops);
};
这与 typedef
关键字相同吗?似乎有一些相关的问题,如so,但我真的不明白那里的解释 .
事实上,因为typename是SO标签之一,我将列出我不理解的解释
typename是C编程语言中的一个关键字,有两个含义 . 首先,它可以用于在模板声明中声明类型参数,并且与“类”同义 . 其次,它可以用于指示从属名称是指类型 . C代码错误的常见原因是省略了必要的类型名称 .
看起来我正在处理第二次使用 . 但我不明白“依赖名称”在这里意味着什么 .
我只是C模板元编程的初学者,所以对上面课程中使用的简单解释会非常有帮助 .
4 回答
简单来说,模板代码中的“依赖名称”是在模板定义内构造的某种类型 .
在您的示例中,CVertex,CEdge,CFace,CHalfEdge类型是模板参数 . 使用参数声明的所有其他名称都是相关的 .
它们可以是类型名称,但可以是其他类型,例如函数或变量的名称 . 编译器必须理解给定的依赖名称是类型还是变量 . 它实际上是编译器相关的 . 要帮助编译器,请添加“typename”以指示此标识符是一种类型 .
想象一下,您的代码没有
#include <vector>
,而是使用前向声明:namespace std { template<class T, class Alloc=allocator<T> > class vector; }
然后编译器不知道类向量中的哪些名称是类型,哪些是成员名称 . 它只知道
vector
是一种类型 .例如,在代码
typename std::vector<TLoop*> m_loops;
中,大多数编译器很可能省略了单词typename
,因为他们知道向量是一种类型 .但是,代码
std::vector<TLoop*>::const_iterator
肯定需要typename
:for (typename std::vector<TLoop*>::const_iterator it = loops().begin(); ...
希望能帮助到你 .
想象一下我实例化
B<A<int>>
. 有效地,编译器将尝试在第二个定义中编写T
的地方替换A<int>
. 问题是,当它到达T::type
时,它没有引用嵌套类型或静态变量 - 两个声明看起来都是一样的 .有时它可以通过使用它的上下文消除歧义,但通常它可以通过使用
typename
关键字告诉它T::thing
是类型的名称 .在您显示的代码中,
typename
是class
的同义词 . 这意味着参数是一种类型 .然而,它在其他环境中有其他用途 . 每当
T1
依赖于模板参数并且你想引用T1::T2
时,你必须说typename T1::T2
,让编译器知道T2
是一个类型 - 否则它被视为函数或变量 .与模板一起使用时,我认为typename的方式是指定typename关键字后面的标识符是一个类型 . 结果是,当使用模板并在模板参数中指定了类型时,C知道它是一个类型并将正确扩展模板 . 这是一种明确的说法,模板参数列表中的某些标识符是类名,例如类名或内置类型或其他类型 .
在某些情况下,上下文可能不清楚模板参数中指定的类型是类型,因此使用typename使其明确无误 .
比如见wikipedia article on typename
这篇文章也可能有所帮助,Template and typename keywords in C++ .