C++ 中括号的不同含义
我对编译器对括号的解释有点困惑。有人可以解释一下在这种情况下实际发生的情况吗?
转换:(int)a
或 int(a)
参数传递:
template <typename t>
int size(t (&)[n]){return n;}
显然,可能有许多不同的上下文,其中括号会改变含义或解释。有人可以解释一下幕后到底发生了什么吗?编译器如何知道如何在每个上下文中进行解释?是否有一般准则或针对每种情况的特定规则?
I am a bit confused with the 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 exactly 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?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
迂腐船长来救援!
如果您编写
This 就是所谓的显式类型转换,并受第 5.2.3 节的约束。确切的措辞是这样说的
(我的重点)。所以这意味着
和
彼此完全相同。您可以选择您认为更容易编写的内容。
至于你的第二个问题,在你给出的模板和数组的例子中,我相信你想要写的是这样的。
这里,
N
和T
是一个模板参数,它允许您传入任何您想要的数组,同时让编译器填充N< /code> 为数组中的元素数量。如果这看起来很混乱(
T (&)[N]
到底是什么?),这是因为这个函数接受T (&)[N] 类型的参数
。为了使它更容易阅读,让我们给这个参数一个名称,如下所示:我认为这使得它更容易阅读。但这个声明意味着什么呢?
这声明了一个名为
array
的变量,它是对恰好包含N
元素的T
数组的引用。您确实可以声明对数组的引用,就像您可以声明指向数组的指针一样。这在实践中并不常见,但在这个特定的模板习惯用法中,编译器尝试将数组与模板参数匹配时,可以很好地为您推断数组的大小。在这种情况下使用括号的原因是,如果您编写
编译器会将其解析为“一个名为
array
的变量,它是一个由N
对象组成的数组,其中每个对象都是一个T&
但是,C++ 规范明确不允许引用数组,这将是非法的,这与函数指针类似 - 您编写而不是
让编译器意识到这一点 。
*
表示functionPointer
是一个指针,而不是返回void *
的函数。至于编译器如何确定何时处理括号。在每种情况下,规则都相当复杂,并且实际上在某些情况下编译器不会以预期的方式解析您的表达式,其中一种情况是编译器通俗地称为“最令人烦恼的解析”。将看起来像对象构造的内容视为函数原型,以下代码:
不创建一个名为
v
的vector
并已初始化。使用默认构造函数。相反,它将其视为名为v
的函数的函数原型,该函数不带参数并生成vector
!但是,如果您要编写Then 编译器可以明确推断这是一个将
10
作为构造函数参数传递的vector
声明,因为不可能它可以被视为函数原型。规范的第 6.8 节和第 8.2 节通过规定任何可以被视为声明的东西以及任何可以被视为函数原型的东西来处理这些情况。数组上下文中括号的情况(即
T (&array)[N]
)由不同的逻辑处理,因为在声明的上下文中变量或定义类型需要显式括号的参数,您的意图不能有任何歧义,因为从上下文中可以清楚地看出您命名类型是为了声明变量。总结一下 -
T(value)
和(T)value
形式的转换是相同的。T (&array)[N]
中的括号是为了防止编译器将&
绑定到T
而不是>array
按预期。Captain Pedantic to the Rescue!
If you write
This is what's known as an explicit type conversion and is governed by §5.2.3. The exact wording says that
(My emphasis). So this means that
and
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.
Here,
N
as well asT
is a template parameter, which allows you to pass in any array that you'd like while having the compiler fill inN
with the number of elements in the array. In case this looks confusing (what on earth isT (&)[N]
?), it's because this function is taking in a parameter of typeT (&)[N]
. To make this a bit easier to read, let's give this parameter a name, as shown here:I think this makes this a bit easier to read. But what does this declaration mean?
This declares a variable called
array
that is a reference to an array ofT
s of exactlyN
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
The compiler would parse this as "a variable called
array
that's an array ofN
objects, each of which is aT&
. 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 writeinstead of
To make the compiler realize that the
*
means thatfunctionPointer
is a pointer, rather than a function that returns avoid *
.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:
Does not create a
vector<int>
calledv
initialized using the default constructor. Instead, it treats this as a function prototype for a function calledv
that takes no arguments and produces avector<int>
! However, if you were to writeThen the compiler can unambiguously infer that this is a declaration of a
vector<int>
passing10
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 -
T(value)
and(T)value
are identical.T (&array)[N]
are to prevent the compiler from binding the&
toT
instead of toarray
as intended.(int)a 是强制转换
int(a) 是 int 的构造,将 a 传递给 int ctor
表达式根据运算符的优先级、元数以及运算符是否是右结合还是左结合。阅读 C++ 文本中的运算符优先级表。
获取程序 c++decl 的副本;它读取 C++ 表达式并输出该表达式的英语语言解释。 或阅读此说明。
(int)a is a cast
int(a) is the construction of an int, passing in a to the int ctor
Expressions are evaluated according to operators' precedence, arity, and whether the operator is right or left associative. Read the operator precedence chart in your C++ text.
Get a copy of the program c++decl; it reads C++ expressions and outputs an English langauge explanation of the expression. Or read this explanation.
从 C++14 附录 A 中,语法中可能出现括号的情况的完整列表如下:
请注意:
if-group
和的预处理器规则elif-group
确实引用了constant-expression
。lparen
表示前面没有空格的(
。raw-string
的规则是在词法分析期间,因此(
和)
不会成为标记。在您的问题中,您使用以下内容:
cast-expression: ( type-id )。 )强制转换表达式
后缀表达式:简单类型说明符(表达式-list_opt)
参数和限定符:(参数声明子句)属性说明符-seq_opt cv-qualifier-seq_opt ref-qualifier_opt 异常规范_opt
noptr-abstract-declarator:( ptr-abstract-declarator )
From C++14 Appendix A, the complete list of cases where parentheses may appear in the grammar is:
Note that:
if-group
andelif-group
do refer toconstant-expression
.lparen
means a(
with no preceding whitespaceraw-string
is during lexing, so the(
and)
do not become tokens.In your question, you use the following:
cast-expression: ( type-id ) cast-expression
postfix-expression: simple-type-specifier ( expression-list_opt )
parameters-and-qualifiers: ( parameter-declaration-clause ) attribute-specifier-seq_opt cv-qualifier-seq_opt ref-qualifier_opt exception-specification_opt
noptr-abstract-declarator: ( ptr-abstract-declarator )