C ++中括号的不同含义? [英] Different meanings of parentheses in C++?

查看:552
本文介绍了C ++中括号的不同含义?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我对编译器对括号的解释有些困惑.有人可以解释一下在这种情况下实际发生什么吗?

投放:(int)aint(a)

参数传递:

template <typename t>
int size(t (&)[n]){return n;}

很明显,可能会有许多不同的上下文,括号会改变含义或解释.有人可以解释一下幕后究竟发生了什么吗?编译器如何知道如何在每种情况下进行解释?是否有针对每个案例的通用指南或特定规则?

谢谢

解决方案

Pedantic船长要救援!

如果你写

int(value)

这就是所谓的显式类型转换,受§ 5.2.3约束.确切的措辞是这样

简单类型说明符(7.1.5)后跟带括号的表达式列表,可在给定表达式列表的情况下构造指定类型的值. 如果表达式列表是单个表达式,则类型转换表达式(在定义上以及含义上)等同于相应的强制转换表达式(5.4)

(我的重点).所以这意味着

int(value)

(int)value

彼此完全相同.您可以根据自己的喜好选择最容易编写的代码.

关于第二个问题,在您提供的模板和数组示例中,我相信您要编写的内容是这样的.

template <typename T, size_t N>
size_t (T (&)[N]) {
    return N;
}

在这里,NT是模板参数,当编译器用数组中的元素数填充N时,它允许您传入想要的任何数组.如果这看起来令人困惑(到底是什么T (&)[N]?),这是因为此函数接受的是类型为T (&)[N]的参数.为了使它更易于阅读,让我们为该参数命名,如下所示:

template <typename T, size_t N>
size_t (T (&array)[N]) {
    return N;
}

我认为这使它更容易阅读.但是这个声明是什么意思?

T (&array)[N]

这将声明一个名为array的变量,该变量是对完全由N元素组成的T数组的引用.实际上,您可以声明对数组的引用,就像可以声明对数组的指针一样.在实践中这不是很常见,但是在此特定的模板习惯用法中,这是让编译器在尝试将数组与模板参数匹配时为您推断数组大小的好方法.

在这种情况下括号的原因是如果您写

T& array[N]

编译器会将其解析为一个名为array的变量,该变量是一个N对象的数组,每个对象都是一个T&.但是,C ++规范明确禁止引用数组,这将是非法的.括号明确地消除了歧义.这类似于函数指针-您编写

void (*functionPointer)()

代替

void *functionPointer()

为了使编译器意识到*意味着functionPointer是指针,而不是返回void *的函数.

关于编译器如何确定何时以各种方式处理括号,规则相当复杂,实际上在某些情况下,编译器不会按预期方式解析表达式.这些情况之一就是俗称的最烦人的解析",在这种情况下,编译器将看起来像对象构造的东西当作函数原型.例如,这段代码:

vector<int> v();

是否创建使用默认构造函数初始化的名为vvector<int>.而是将其视为名为v的函数的函数原型,该函数不带任何参数并生成一个vector<int>!但是,如果您要写

vector<int> v(10);

然后,编译器可以明确地推断这是vector<int>的声明,并将10作为构造函数参数传递,因为无法将其视为函数原型.规范的§ 6.8和§ 8.2指出,可以被视为声明的任何内容都将被处理,并且可以被视为函数原型的所有内容也将被处理.

数组上下文(即T (&array)[N])中括号的情况由另一段逻辑处理,因为在上下文中声明变量或定义类型需要显式括号的参数,因此您的意图没有任何歧义,因为从上下文中可以清楚地看出,您在命名类型是为了声明变量.

总结-

  1. T(value)(T)value形式的广播相同.
  2. T (&array)[N]中的括号是为了防止编译器将&绑定到T而不是按预期的方式绑定到array.
  3. 通常从上下文中推断出括号的特殊用法,尽管在变量声明和函数原型之间可能会出现一些问题.

希望这会有所帮助!

I am a bit confused withnthe interpretation of parentheses by the compiler. Can some one please explain what actually happens in such contexts?

Casting: (int)a or int(a)

Parameter passing:

template <typename t>
int size(t (&)[n]){return n;}

Obviously there could be many different contexts where parentheses change the meaning or interpretation. Can some one please explain what exaactly is happening behind the curtain? How does the compiler know how to interpret in each context? Is there a general guideline or is it a specific rule for each case?

Thanks

解决方案

Captain Pedantic to the Rescue!

If you write

int(value)

This is what's known as an explicit type conversion and is governed by §5.2.3. The exact wording says that

A simple-type-specifier (7.1.5) followed by a parenthesized expression-list constructs a value of the specified type given the expression list. If the expression list is a single expression, the type conversion expression is equivalent (in definedness, and if defined in meaning) to the corresponding cast expression (5.4)

(My emphasis). So this means that

int(value)

and

(int)value

are completely identical to one another. It's up to you to pick whichever of these you find easier to write.

As for your second question, in the example you gave with the templates and array, I believe that what you meant to write was something like this.

template <typename T, size_t N>
size_t (T (&)[N]) {
    return N;
}

Here, N as well as T is a template parameter, which allows you to pass in any array that you'd like while having the compiler fill in N with the number of elements in the array. In case this looks confusing (what on earth is T (&)[N]?), it's because this function is taking in a parameter of type T (&)[N]. To make this a bit easier to read, let's give this parameter a name, as shown here:

template <typename T, size_t N>
size_t (T (&array)[N]) {
    return N;
}

I think this makes this a bit easier to read. But what does this declaration mean?

T (&array)[N]

This declares a variable called array that is a reference to an array of Ts of exactly N elements. You can indeed declare references to arrays, just as you can declare pointers to arrays. This is not very common in practice, but in this particular template idiom is a great way of having the compiler infer the size of the array for you as it tries to match the array to the template argument.

The reason for the parentheses in this case is that if you write

T& array[N]

The compiler would parse this as "a variable called array that's an array of N objects, each of which is a T&. However, the C++ spec specifically disallows arrays of references, and this would be illegal. The parentheses explicitly disambiguate this. This is similar to function pointers - you write

void (*functionPointer)()

instead of

void *functionPointer()

To make the compiler realize that the * means that functionPointer is a pointer, rather than a function that returns a void *.

As for how the compiler determines when to treat parentheses in each way, the rules are fairly complex and there are actually a few circumstances in which the compiler will not parse your expression in the intended way. One of these cases is something colloquially referred to as "the most vexing parse" in which the compiler treats what looks like object construction as a function prototype. As an example, this code:

vector<int> v();

Does not create a vector<int> called v initialized using the default constructor. Instead, it treats this as a function prototype for a function called v that takes no arguments and produces a vector<int>! However, if you were to write

vector<int> v(10);

Then the compiler can unambiguously infer that this is a declaration of a vector<int> passing 10 as a constructor argument, because there's no way that it could be treated as a function prototype. §6.8 and §8.2 of the spec handles these cases by saying that anything that can be treated as a declaration will be, and anything that can be treated as a function prototype will be as well.

The case of parentheses in the context of the array (that is, T (&array)[N]) is handled by a different piece of logic because in the context in which you're declaring a variable or defining a parameter whose type requires explicit parenthesis, there can be no ambiguity about your intention because it's clear from context that you're naming a type in order to declare a variable.

To summarize -

  1. Casts of the form T(value) and (T)value are identical.
  2. The parentheses in T (&array)[N] are to prevent the compiler from binding the & to T instead of to array as intended.
  3. The particular use of parenthesis is usually inferred from context, though some issues can come up between variable declarations and function prototypes.

Hope this helps!

这篇关于C ++中括号的不同含义?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆