In order to parse a C++ program, the compiler needs to know whether certain names are types or not.
(为了解析C ++程序,编译器需要知道某些名称是否为类型。)
The following example demonstrates that: (以下示例说明了这一点:)
t * f;
How should this be parsed?
(应该如何解析?)
For many languages a compiler doesn't need to know the meaning of a name in order to parse and basically know what action a line of code does. (对于许多语言,编译器不需要知道名称的含义即可进行解析,并且基本上知道一行代码会执行什么操作。)
In C++, the above however can yield vastly different interpretations depending on what t
means. (然而,在C ++中,根据t
含义,以上内容可能会产生截然不同的解释。)
If it's a type, then it will be a declaration of a pointer f
. (如果是类型,则它将是指针f
的声明。)
However if it's not a type, it will be a multiplication. (但是,如果不是类型,它将是一个乘法。)
So the C++ Standard says at paragraph (3/7): (因此,C ++标准在第(3/7)段中说:)
Some names denote types or templates.
(一些名称表示类型或模板。)
In general, whenever a name is encountered it is necessary to determine whether that name denotes one of these entities before continuing to parse the program that contains it. (通常,无论何时遇到名称,都必须在继续解析包含该名称的程序之前确定该名称是否表示这些实体之一。)
The process that determines this is called name lookup. (确定此过程的过程称为名称查找。)
How will the compiler find out what a name t::x
refers to, if t
refers to a template type parameter?
(如果t
引用模板类型参数,编译器将如何找出名称t::x
所指?)
x
could be a static int data member that could be multiplied or could equally well be a nested class or typedef that could yield to a declaration. (x
可以是可以乘以的静态int数据成员,也可以是可以产生声明的嵌套类或typedef。)
If a name has this property - that it can't be looked up until the actual template arguments are known - then it's called a dependent name (it "depends" on the template parameters). (如果名称具有此属性-在知道实际的模板参数之前不能查找它-那么它被称为从属名称 (它“取决于”模板参数)。)
You might recommend to just wait till the user instantiates the template:
(您可能建议仅等待用户实例化模板:)
Let's wait until the user instantiates the template, and then later find out the real meaning of t::x * f;
(让我们等到用户实例化模板,然后再找出t::x * f;
的真实含义t::x * f;
)
This will work and actually is allowed by the Standard as a possible implementation approach.
(这将是可行的,并且实际上是标准允许的一种可能的实施方法。)
These compilers basically copy the template's text into an internal buffer, and only when an instantiation is needed, they parse the template and possibly detect errors in the definition. (这些编译器基本上将模板的文本复制到内部缓冲区中,并且仅当需要实例化时,它们才会解析模板并可能检测到定义中的错误。)
But instead of bothering the template's users (poor colleagues!) with errors made by a template's author, other implementations choose to check templates early on and give errors in the definition as soon as possible, before an instantiation even takes place. (但是,其他实现方式没有使模板的用户(可怜的同事!)受到模板作者的错误困扰,而是选择尽早检查模板,并在实例化发生之前尽快给出定义错误。)
So there has to be a way to tell the compiler that certain names are types and that certain names aren't.
(因此,必须有一种方法告诉编译器某些名称是类型,而某些名称不是。)
The "typename" keyword (“类型名称”关键字)
The answer is: We decide how the compiler should parse this.
(答案是: 我们决定编译器应如何解析它。)
If t::x
is a dependent name, then we need to prefix it by typename
to tell the compiler to parse it in a certain way. (如果t::x
是从属名称,则我们需要在其typename
加上类型名,以告知编译器以某种方式对其进行解析。)
The Standard says at (14.6/2): (标准在(14.6 / 2)中说:)
A name used in a template declaration or definition and that is dependent on a template-parameter is assumed not to name a type unless the applicable name lookup finds a type name or the name is qualified by the keyword typename.
(除非在适用的名称查找中找到类型名称或该名称由关键字typename限定,否则假定模板声明或定义中使用的且依赖于模板参数的名称不会命名类型。)
There are many names for which typename
is not necessary, because the compiler can, with the applicable name lookup in the template definition, figure out how to parse a construct itself - for example with T *f;
(有许多名称不需要使用typename
,因为编译器可以通过模板定义中的适用名称查找来弄清楚如何解析结构本身-例如,使用T *f;
)
, when T
is a type template parameter. (,当T
是类型模板参数时。)
But for t::x * f;
(但是对于t::x * f;
)
to be a declaration, it must be written as typename t::x *f;
(要成为声明,必须将其写为typename t::x *f;
)
. (。)
If you omit the keyword and the name is taken to be a non-type, but when instantiation finds it denotes a type, the usual error messages are emitted by the compiler. (如果省略关键字,并且名称被视为非类型,但是当实例化发现它表示类型时,编译器会发出通常的错误消息。)
Sometimes, the error consequently is given at definition time: (有时,错误因此在定义时给出:)
// 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;
The syntax allows typename
only before qualified names - it is therefor taken as granted that unqualified names are always known to refer to types if they do so.
(该语法允许typename
仅前限定的名字 -它是为此视为理所当然的认为不合格的名字总是已知是指类型,如果他们这样做。)
A similar gotcha exists for names that denote templates, as hinted at by the introductory text.
(正如介绍性文字所暗示的,对于表示模板的名称也存在类似的陷阱。)
The "template" keyword (“模板”关键字)
Remember the initial quote above and how the Standard requires special handling for templates as well?
(还记得上面的最初引用以及标准如何要求对模板进行特殊处理吗?)
Let's take the following innocent-looking example: (让我们看下面的例子:)
boost::function< int() > f;
It might look obvious to a human reader.
(对于人类读者来说,这似乎很明显。)
Not so for the compiler. (对于编译器则不是这样。)
Imagine the following arbitrary definition of boost::function
and f
: (想象以下boost::function
和f
任意定义:)
namespace boost { int function = 0; }
int main() {
int f = 0;
boost::function< int() > f;
}
That's actually a valid expression !
(这实际上是一个有效的表达式 !)
It uses the less-than operator to compare boost::function
against zero ( int()
), and then uses the greater-than operator to compare the resulting bool
against f
. (它使用小于运算符比较boost::function
与零( int()
),然后使用大于运算符比较生成的bool
与f
。)
However as you might well know, boost::function
in real life is a template, so the compiler knows (14.2/3): (但是,您可能知道, 现实生活中的boost::function
是一个模板,因此编译器知道(14.2 / 3):)
After name lookup (3.4) finds that a name is a template-name, if this name is followed by a <, the < is always taken as the beginning of a template-argument-list and never as a name followed by the less-than operator.
(在名称查找(3.4)发现名称是模板名称之后,如果此名称后跟<,则始终将<视为模板参数列表的开头,而永远不要将其作为后跟-的名称。比运算符。)
Now we are back to the same problem as with typename
.
(现在我们回到与typename
相同的问题。)
What if we can't know yet whether the name is a template when parsing the code? (如果在解析代码时我们还不知道名称是否是模板怎么办?)
We will need to insert template
immediately before the template name, as specified by 14.2/4
. (我们需要在模板名称之前紧接插入template
,如14.2/4
所指定。)
This looks like: (看起来像:)
t::template f<int>(); // call a function template
Template names can not only occur after a ::
but also after a ->
or .
(模板名称不仅可以出现在::
而且可以出现在->
或之后.
)
in a class member access. (在班级成员访问中。)
You need to insert the keyword there too: (您还需要在其中插入关键字:)
this->template f<int>(); // call a function template
Dependencies (依存关系)
For the people that have thick Standardese books on their shelf and that want to know what exactly I was talking about, I'll talk a bit about how this is specified in the Standard.
(对于那些架子上堆满Standardese书籍,又想知道我到底在说什么的人,我会说一些有关Standard中如何指定的内容。)
In template declarations some constructs have different meanings depending on what template arguments you use to instantiate the template: Expressions may have different types or values, variables may have different types or function calls might end up calling different functions.
(在模板声明中,某些构造具有不同的含义,具体取决于用于实例化模板的模板参数:表达式可能具有不同的类型或值,变量可能具有不同的类型,或者函数调用最终可能会调用不同的函数。)
Such constructs are generally said to depend on template parameters. (通常说这样的构建体取决于模板参数。)
The Standard defines precisely the rules by whether a construct is dependent or not.
(该标准通过构造是否依赖来精确定义规则。)
It separates them into logically different groups: One catches types, another catches expressions. (它将它们分成逻辑上不同的组:一个捕获类型,另一个捕获表达式。)
Expressions may depend by their value and/or their type. (表达式可能取决于它们的值和/或类型。)
So we have, with typical examples appended: (因此,我们附有典型示例:)
Most of the rules are intuitive and are built up recursively: For example, a type constructed as T[N]
is a dependent type if N
is a value-dependent expression or T
is a dependent type.
(大多数规则是直观的,并且是递归建立的:例如,如果N
是一个值相关的表达式或T
是一个依赖类型,则构造为T[N]
的类型是一个依赖类型。)
The details of this can be read in section (14.6.2/1
) for dependent types, (14.6.2.2)
for type-dependent expressions and (14.6.2.3)
for value-dependent expressions. (有关详细信息,请参阅(14.6.2/1
)部分中的相关类型, (14.6.2.2)
中的类型相关表达式,以及(14.6.2.3)
中的值相关表达式。)
Dependent names (相关名称)
The Standard is a bit unclear about what exactly is a dependent name .
(该标准对于从属名称 <e