C++ 什么时候开始;typename";有必要吗?
可能重复:C++ 什么时候开始;typename";有必要吗?,c++,templates,syntax,typename,C++,Templates,Syntax,Typename,可能重复: 考虑以下代码: template<class K> class C { struct P {}; vector<P> vec; void f(); }; template<class K> void C<K>::f() { typename vector<P>::iterator p = vec.begin(); } 模板 C类{ 结构P{}; 向量vec; 无效f(); }; 模板v
考虑以下代码:
template<class K>
class C {
struct P {};
vector<P> vec;
void f();
};
template<class K> void C<K>::f() {
typename vector<P>::iterator p = vec.begin();
}
模板
C类{
结构P{};
向量vec;
无效f();
};
模板void C::f(){
typename向量
::迭代器P=vec.begin();
}
为什么在这个例子中需要“typename”关键字?
是否还有其他必须指定“typename”的情况?每当类型名依赖于模板参数时,都需要使用typename关键字(这样编译器就可以“知道”标识符(类型或值)的语义,而不必在第一次传递时有完整的符号表)
在使用通用模板参数时,lone typename关键字也可能很有用,但含义不同,且不太常见:
#包括
#包括
#包括
模板
结构容器测试
{
typedef容器IntContainer;
typedef容器StringContainer;
//
void DoTests()
{
ints集装箱ints;
字符串容器字符串;
//…等等
}
};
int main()
{
集装箱测试t1;
集装箱测试t2;
t1.DoTests();
t2.DoTests();
}
需要类型名
关键字,因为迭代器
是p
的依赖类型。编译器无法猜测迭代器是引用了一个值还是一个类型,因此除非您大叫typename
,否则它将假定它是一个值。在类型或值都有效的上下文中,只要存在依赖于模板参数的类型,就需要它。例如,由于基类必须是类型,因此不需要as基类typename
在同一主题上,有一个
template
关键字用于让编译器知道某个依赖名称是一个模板函数而不是一个值。简短回答:每当引用作为依赖名称的嵌套名称时,即嵌套在具有未知参数的模板实例中
详细回答:C++中有三层实体:值、类型和模板。所有这些都可以有名称,而名称本身并不能告诉您它是实体的哪一层。相反,关于名称实体性质的信息必须从上下文中推断出来
如果无法进行此推断,则必须指定:
template <typename> struct Magic; // defined somewhere else
template <typename T> struct A
{
static const int value = Magic<T>::gnarl; // assumed "value"
typedef typename Magic<T>::brugh my_type; // decreed "type"
// ^^^^^^^^
void foo() {
Magic<T>::template kwpq<T>(1, 'a', .5); // decreed "template"
// ^^^^^^^^
}
};
用法:
int main()
{
A<int> a;
a.foo();
return Magic<signed char>::kwpq<float>(2, 3); // no disambiguation here!
}
intmain()
{
A A;
a、 foo();
return Magic::kwpq(2,3);//这里没有消歧!
}
我以前从来都不知道“孤独的typename”,太酷了@Nils:<代码> const > C++无效。谢谢解释。但我不能理解最后一件事:由于名称Magic::kwpq
依赖于模板参数t
,这将在两阶段查找的第二阶段解决,对吗?那么,为什么编译器当时不能检查(当他能够确定kwpq
是一个模板还是一个类型或任何东西时)名称是否根据其实体层正确使用?@PaoloM:class templatea
的成员函数的定义必须在第一阶段进行解析,因此,您需要消除歧义才能使语法有意义。在第二阶段,我们检查具体类型T
的实例化Magic
是否实际有一个成员kwpq
,该成员是具有适当签名的函数。(感谢您的编辑!)
template <typename T> struct Magic
{
static const T gnarl;
typedef T & brugh;
template <typename S> static void kwpq(int, char, double) { T x; }
};
template <> struct Magic<signed char>
{
// note that `gnarl` is absent
static constexpr long double brugh = 0.25; // `brugh` is now a value
template <typename S> static int kwpq(int a, int b) { return a + b; }
};
int main()
{
A<int> a;
a.foo();
return Magic<signed char>::kwpq<float>(2, 3); // no disambiguation here!
}