C++ 我必须在哪里以及为什么要把;模板";及;typename";关键词?
在模板中,我必须将C++ 我必须在哪里以及为什么要把;模板";及;typename";关键词?,c++,templates,typename,c++-faq,dependent-name,C++,Templates,Typename,C++ Faq,Dependent Name,在模板中,我必须将typename和template放在从属名称上的位置和原因是什么? 到底什么是从属名称 我有以下代码: template <typename T, typename Tail> // Tail will be a UnionNode too. struct UnionNode : public Tail { // ... template<typename U> struct inUnion { // Q: where
typename
和template
放在从属名称上的位置和原因是什么?到底什么是从属名称 我有以下代码:
template <typename T, typename Tail> // Tail will be a UnionNode too.
struct UnionNode : public Tail {
// ...
template<typename U> struct inUnion {
// Q: where to add typename/template here?
typedef Tail::inUnion<U> dummy;
};
template< > struct inUnion<T> {
};
};
template <typename T> // For the last node Tn.
struct UnionNode<T, void> {
// ...
template<typename U> struct inUnion {
char fail[ -2 + (sizeof(U)%2) ]; // Cannot be instantiated for any U
};
template< > struct inUnion<T> {
};
};
template//Tail也将是一个UnionNode。
结构UnionNode:公共尾部{
// ...
模板结构inUnion{
//问:在这里哪里添加typename/模板?
typedef-Tail::inUnion-dummy;
};
模板<>结构单元{
};
};
模板//用于最后一个节点Tn。
结构联合节点{
// ...
模板结构inUnion{
char fail[-2+(sizeof(U)%2)];//无法为任何U实例化
};
模板<>结构单元{
};
};
我遇到的问题在typedef Tail::inUnion dummy
行中。我相当肯定,inUnion
是一个依赖的名称,VC++完全正确地扼杀了它。我还知道我应该能够在某个地方添加
模板
,告诉编译器inUnion是一个模板id。但是具体在哪里呢?然后,它是否应该假设inUnion是一个类模板,即inUnion
命名一个类型而不是一个函数?typedef typename Tail::inUnion dummy;
typedef typename Tail::inUnion<U> dummy;
然而,我不确定您对inUnion的实现是否正确。如果我理解正确的话,这个类不应该被实例化,因此“fail”选项卡永远不会失败。也许最好用一个简单的布尔值指示类型是否在并集中
template <typename T, typename TypeList> struct Contains;
template <typename T, typename Head, typename Tail>
struct Contains<T, UnionNode<Head, Tail> >
{
enum { result = Contains<T, Tail>::result };
};
template <typename T, typename Tail>
struct Contains<T, UnionNode<T, Tail> >
{
enum { result = true };
};
template <typename T>
struct Contains<T, void>
{
enum { result = false };
};
模板结构包含;
样板
结构包含
{
枚举{result=Contains::result};
};
样板
结构包含
{
枚举{result=true};
};
样板
结构包含
{
枚举{result=false};
};
附:看一看
PS2:请看,尤其是在Andrei Alexandrescu的书中:现代C++设计
(参阅)
< >为了分析C++程序,编译器需要知道某些名称是否为类型。以下示例说明:t * f;
这应该如何解析?对于许多语言,编译器不需要知道名称的含义就可以解析代码,并且基本上知道一行代码的作用。然而,C++中,根据代码< > <代码>的含义,可以产生很大不同的解释。如果它是一个类型,那么它将是指针f
的声明。然而,如果它不是一个类型,它将是一个乘法。因此,C++标准在第(3/7)段:
有些名称表示类型或模板。通常,每当遇到名称时,在继续解析包含该名称的程序之前,必须确定该名称是否表示这些实体之一。确定这一点的过程称为名称查找
如果t
引用模板类型参数,编译器将如何找出名称t::x
引用的是什么x
可以是可以相乘的静态int数据成员,也可以是可以生成声明的嵌套类或typedef如果名称具有此属性(在知道实际模板参数之前无法查找),则称为从属名称(它“取决于”模板参数)。
您可能建议等待用户实例化模板:
让我们等到用户实例化模板,然后再找出t::x*f的真正含义代码>
这将起作用,并且实际上是标准允许的一种可能的实现方法。这些编译器基本上将模板的文本复制到内部缓冲区中,并且仅当需要实例化时,才解析模板并可能检测定义中的错误。但是,其他实现没有因为模板作者的错误而困扰模板的用户(可怜的同事!),而是选择尽早检查模板,并在实例化之前尽快给出定义中的错误
因此,必须有一种方法告诉编译器某些名称是类型,而某些名称不是类型
“typename”关键字
答案是:我们决定编译器应该如何解析它。如果t::x
是一个依赖名称,那么我们需要用typename
作为前缀,告诉编译器以某种方式解析它。该标准规定为(14.6/2):
模板声明或定义中使用的、依赖于模板参数的名称是
假定不命名类型,除非适用的名称查找找到类型名称或名称是限定的
通过关键字typename
有许多名称不需要typename
,因为编译器可以通过模板定义中适用的名称查找,找出如何解析构造本身-例如使用T*f代码>,当T
是类型模板参数时。但是对于t::x*f
要成为一个声明,它必须写成typename t::x*f代码>。如果省略关键字并且名称被视为非类型,但当实例化发现它表示类型时,编译器会发出通常的错误消息。有时,在定义时给出误差:
// t::x is taken as non-type, but as an expression the following misses an
// operator between the two names or a semicolon separating them.
t::x f;
语法只允许在限定名称之前使用typename
——因此,如果非限定名称引用类型,则通常认为它们引用类型是理所当然的
正如介绍性文本所暗示的,对于表示模板的名称也存在类似的问题
“模板”关键字
还记得上面的初始引用以及标准如何要求对模板进行特殊处理吗?让我们举一个看起来很无辜的例子:
boost::function< int() > f;
这实际上是一个有效的表达式!它使用小于运算符将boost::function
与零(int()
)进行比较,然后使用较大的
namespace boost { int function = 0; }
int main() {
int f = 0;
boost::function< int() > f;
}
t::template f<int>(); // call a function template
this->template f<int>(); // call a function template
template <typename T, typename Tail>
struct UnionNode : public Tail {
// ...
template<typename U> struct inUnion {
typedef typename Tail::template inUnion<U> dummy;
};
// ...
};
typename t::template iterator<int>::value_type v;
template <typename T>
struct derive_from_Has_type : /* typename */ SomeBase<T>::type
{ };
template <typename T>
struct derive_from_Has_type : SomeBase<T> {
using SomeBase<T>::template type; // error
using typename SomeBase<T>::type; // typename *is* allowed
};
template<typename T>
struct A {
typedef int result_type;
void f() {
// error, "this" is dependent, "template" keyword needed
this->g<float>();
// OK
g<float>();
// error, "A<T>" is dependent, "typename" keyword needed
A<T>::result_type n1;
// OK
result_type n2;
}
template<typename U>
void g();
};
struct B {
typedef int result_type;
};
template<typename T>
struct C { }; // could be specialized!
template<typename T>
struct D : B, C<T> {
void f() {
// OK, member of current instantiation!
// A::result_type is not dependent: int
D::result_type r1;
// error, not a member of the current instantiation
D::questionable_type r2;
// OK for now - relying on C<T> to provide it
// But not a member of the current instantiation
typename D::questionable_type r3;
}
};
template<>
struct C<int> {
typedef bool result_type;
typedef int questionable_type;
};
void h() {
typename A<T>::questionable_type x;
}
struct B { void f(); };
struct A : virtual B { void f(); };
template<typename T>
struct C : virtual B, T {
void g() { this->f(); }
};
int main() {
C<A> c; c.g();
}
template<typename T>
struct test {
using type = T; // no typename required
using underlying_type = typename T::type // typename required
};
template<typename T>
struct test {
// typename required
using type = typename std::conditional<true, const T&, T&&>::type;
// no typename required
using integer = std::conditional<true, int, float>::type;
};
template<typename T>
struct test {
template<typename U>
void get() const {
std::cout << "get\n";
}
};
template<typename T>
void func(const test<T>& t) {
t.get<int>(); // error
}
template<class T> void f_tmpl () { T::foo * x; /* <-- (A) */ }
struct X { typedef int foo; }; /* (C) --> */ f_tmpl<X> ();
struct Y { static int const foo = 123; }; /* (D) --> */ f_tmpl<Y> ();
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
}
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
}
namespace N {
template<class T>
struct X { };
}
N:: X<int> a; // ... legal
typename N::template X<int> b; // (K), legal
typename template X<int> c; // (L), ill-formed
// .------- the base-specifier-list
template<class T> // v
struct Derived : typename SomeTrait<T>::type /* <- ill-formed */ {
...
};
struct Base {
template<class T>
struct type { };
};
struct Derived : Base {
using Base::template type; // ill-formed
using Base::type; // legal
};
template< typename T > void foo( T& x, std::string str, int count )
{
// these names are looked up during the second phase
// when foo is instantiated and the type T is known
x.size(); // dependant name (non-type)
T::instance_count ; // dependant name (non-type)
typename T::iterator i ; // dependant name (type)
// during the first phase,
// T::instance_count is treated as a non-type (this is the default)
// the typename keyword specifies that T::iterator is to be treated as a type.
// these names are looked up during the first phase
std::string::size_type s ; // non-dependant name (type)
std::string::npos ; // non-dependant name (non-type)
str.empty() ; // non-dependant name (non-type)
count ; // non-dependant name (non-type)
}
class A { public: typedef int type; static const int val { 1 }; };
class B { public: typedef float type; static const int val { 2 }; };
template<typename T> class C {};
template<int I> class D {};
template<typename T> class X {
T::type v; // OK
T::type f(T::type arg) { return arg; } // OK
T::type g(double arg) { return static_cast<T::type>(arg); } // OK
// C<T::type> c1; // error
D<T::val> d; // OK (as has always been)
C<typename T::type> c2; // OK (old style)
typedef T::type mytype; // OK
using mytypeagain = T::type; // OK
C<mytype> c3; // OK (via typedef / using)
};
X<A> xa;
X<B> xb;
template <class T>
struct DependentType
{
typename T::type a;
using Type=typename T::type;
};
template <class T>
struct DependentTemplate
{
// template function
template <class U>
static void func() {}
// template class
template <class U>
struct ClassName{};
};
template <class T1, class T2>
void foo()
{
// 3 ways to call a dependent template function
DependentTemplate<T1>::template func<T2>();
DependentTemplate<T1>().template func<T2>();
(new DependentTemplate<T1>())->template func<T2>();
// You need both typename and template to reference a dependent template class
typename DependentTemplate<T1>::template ClassName<T2> obj;
using Type=typename DependentTemplate<T1>::template ClassName<T2>;
}