2013-04-21 109 views
3

类模板纠正错误最近,我读的书:C++ templates: the complete guide大卫Vandevoorde和尼古拉M.约祖蒂斯写的。gcc编译器不会显示与注射名称

具体地约模板解析从书页126

Class templates also have injected class names, However, they are stranger than ordinary injected class names: They can be followed by template arguments (in which case they are injected class template names), but if they are not followed by template arguments they represent the class with its parameters as its arguments (or, for a partial specialization, its specialization arguments).

相关码从书除外如下引用:

template<template<typename> class TT> 
class X 
{ 
}; 

template <typename T> 
class C 
{ 
    C* a; //OK, same as "C<T>* a" 
    C<void> b; // OK 
    X<C> c; //Error, C without a template argument list does not denote a template 
    X< ::C>d; 
}; 

int main() 
{ 
    return 0; 
} 

上面的代码示例试图解释援引整体段。

我编译上面的代码中的gcc 4.5.3,其输出:

error: field ‘b’ has incomplete type 

因此,我有以下问题:

  1. 为什么编译器生成完全不同的错误讯息?该书说b是可以的,但gcc出错了;与此同时,书中列出的其他错误没有被发现?为什么,这是书中可能出现的编译器错误或错误?
  2. 是什么injected class names意思?如何才能辨别哪些名字是injected class names,哪些不是?
  3. 为什么C*a是一样的C<T>* a?我试着用C<T>* a更换C*a,未报告任何错误,所以是C* aC<T>* a的简写?

非常感谢!

+0

这句法:'模板<模板类TT>'似乎并没有合法的副手我......你确定你正确转录的例子吗? – 2013-04-21 03:53:07

+0

@NathanErnst我是这么认为的,我从书上抄的代码,并检查其是同 – taocp 2013-04-21 03:53:53

+0

'错误,C没有一个模板参数列表不表示template',我没有看到这个错误出现 – iammilind 2013-04-21 03:55:39

回答

2

注意:注入类名称只是用于声明类的标识符(与其他名称也指相同的类,如typedef名称相反)。

下面是从C++ 11标准的相关报价,节14.6.1p1:

Like normal (non-template) classes, class templates have an injected-class-name (Clause 9). The injected-class-name can be used as a template-name or a type-name. When it is used with a template-argument-list, as a template-argument for a template template-parameter, or as the final identifier in the elaborated-type-specifier of a friend class template declaration, it refers to the class template itself. Otherwise, it is equivalent to the template-name followed by the template-parameters of the class template enclosed in <> .

所以很明显,这是合法的C++ 11。

然而,该书正确地描述的C++ 03的行为:

Like normal (non-template) classes, class templates have an injected-class-name (clause 9). The injected-class-name can be used with or without a template-argument-list. When it is used without a template-argument-list, it is equivalent to the injected-class-name followed by the template-parameters of the class template enclosed in <> . When it is used with a template-argument-list, it refers to the specified class template specialization, which could be the current specialization or another specialization.

从反转逻辑除了,我们看到,C++ 03包含在一个情况下标识符称为模板(当提供了模板参数),并且C++ 11增加了两个额外的案例,其中一个会影响此代码。

所以在C++ 03中,代码相当于X<C<T>> c;,这是一个错误,因为X需要传递模板而不是类型。

底线:为了学习语言,尤其是模板,您需要a book on C++11。旧版书籍在建筑和高层次设计方面仍然有用,但不能解释在出版后发生变化的语言错综复杂。

0

我认为这本书忘*

C<void> *b; 

否则,声明不即使出模板有效。因为编译器到达该行时C尚未完全声明。这与尝试使用前向声明类相同。

例如,这是无效的。

class A { 
    A a; 
    ^// A has incomplete type here 
}; 

但是,这是有效的。

class A { 
    A *a; 
}; 

注入的类名是当一个类的模板参数在类的自己的作用域注入与它的用途。

tempalte<typename T> 
class C { 
    C* a; // same as C<T>* a; 
}; 

我认为这本书完全解释了它。


so is C* a a shorthand for C<T>* a ?

只有类本身的范围之内。 (包括成员定义范围)例如

template <typename T> 
void C<T>::f() { 
    C a;   // Same as C<T> a; 
} 

Why the compiler generates totally different error messages? the book says b is OK, but gcc gave the error; meanwhile, other errors listed in the book are not detected? Why, is this a possible compiler bug or error in book?

上面除了东西解释,其原因可能是,这本书是比较老的,从那时起编译器已经改变。你不能指望错误消息是完全一样的。

1

试图回答您的问题:

  1. 不同的编译器各供应商和版本产生不同的诊断。你不能依靠从一个到另一个的确切消息。

  2. “注入的类名” §9下在标准中定义,第2段:

A class-name is inserted into the scope in which it is declared immediately after the class-name is seen. The class-name is also inserted into the scope of the class itself; this is known as the injected-class-name. For purposes of access checking, the injected-class-name is treated as if it were a public member name. A class-specifier is commonly referred to as a class definition. A class is considered defined after the closing brace of its class-specifier has been seen even though its member functions are in general not yet defined. The optional attribute-specifier-seq appertains to the class; the attributes in the attribute-specifier-seq are thereafter considered attributes of the class whenever it is named.

  1. 原因C* a相同C<T>* a是由于上下文:两个内发生C的声明。 C++允许有一个“快捷方式”,因为模板类可以引用它自己的实例化,而在可以假定参数的上下文中没有模板参数(这是其中之一)。如果你想参考C与不同的模板参数的实例化,你需要明确它。

你得到您的特定错误的原因是,C<void>处于使你试图实例化不同的模板参数的C的时间不完全类型。我认为它应该干净地编译,因为你永远不会实例化任何模板,所以C的类型完整性应该不重要。

+0

它是两相名称查找,并且所述第一阶段确定的名称指的是“当前模板的未知专业化”。但是C++ 03没有这个概念。 – 2013-04-21 05:51:27