Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
426 views
in Technique[技术] by (71.8m points)

c++ - 为什么必须在何处以及为什么要放置“模板”和“类型名”关键字?(Where and why do I have to put the “template” and “typename” keywords?)

In templates, where and why do I have to put typename and template on dependent names?

(在模板中,为什么必须在哪里以及为什么要在依赖名称上放置typenametemplate ?)

What exactly are dependent names anyway?

(无论如何,从属名称到底是什么?)

I have the following code:

(我有以下代码:)

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> {
    };
};

The problem I have is in the typedef Tail::inUnion<U> dummy line.

(我typedef Tail::inUnion<U> dummy的问题是在typedef Tail::inUnion<U> dummy行中。)

I'm fairly certain that inUnion is a dependent name, and VC++ is quite right in choking on it.

(我相当确定inUnion是一个从属名称,而VC ++ inUnion可以使它窒息。)

I also know that I should be able to add template somewhere to tell the compiler that inUnion is a template-id.

(我也知道我应该能够在某个地方添加template ,以告诉编译器inUnion是模板ID。)

But where exactly?

(但是到底在哪里?)

And should it then assume that inUnion is a class template, ie inUnion<U> names a type and not a function?

(然后是否应该假设inUnion是一个类模板,即inUnion<U>是一个类型而不是一个函数?)

  ask by MSalters translate from so

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

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::functionf任意定义:)

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() ),然后使用大于运算符比较生成的boolf 。)

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:

(因此,我们附有典型示例:)

  • Dependent types (eg: a type template parameter T )

    (从属类型(例如:类型模板参数T ))

  • Value-dependent expressions (eg: a non-type template parameter N )

    (依赖于值的表达式(例如:非类型模板参数N ))

  • Type-dependent expressions (eg: a cast to a type template parameter (T)0 )

    (类型相关的表达式(例如:转换为类型模板参数(T)0 ))

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


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...