我对编译器对括号的解释感到有点困惑。有人可以解释在这种情况下究竟发生了什么吗?
施法:(int)a
或int(a)
参数传递:
template <typename t>
int size(t (&)[n]){return n;}
显然,可能存在许多不同的语境,其中括号改变了含义或解释。有人可以解释幕后发生的事情吗?编译器如何知道如何在每个上下文中进行解释?是否有一般指导方针,或者是针对每个案例的具体规则?
由于
答案 0 :(得分:22)
Capant 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;
}
此处,N
以及T
是一个模板参数,它允许您在编译器使用数字填充N
时传入您想要的任何数组数组中的元素。如果这看起来很混乱(究竟是T (&)[N]
?),那是因为这个函数接受了类型为T (&)[N]
的参数。为了使这更容易阅读,让我们给这个参数一个名字,如下所示:
template <typename T, size_t N>
size_t (T (&array)[N]) {
return N;
}
我认为这使得阅读更容易一些。但这个宣言意味着什么?
T (&array)[N]
这声明了一个名为array
的变量,它是对T
个N
元素数组的引用。您确实可以声明对数组的引用,就像您可以声明指向数组的指针一样。这在实践中并不常见,但在这个特定的模板中,成语是让编译器在尝试将数组与模板参数匹配时推断出数组大小的好方法。
在这种情况下括号的原因是,如果你写
T& array[N]
编译器会将此解析为“一个名为array
的变量,它是N
个对象的数组,每个对象都是T&
。但是,C ++规范明确禁止引用数组,这将是非法的。括号明确消除歧义。这类似于函数指针 - 你写的
void (*functionPointer)()
而不是
void *functionPointer()
使编译器意识到*
意味着functionPointer
是一个指针,而不是一个返回void *
的函数。
至于编译器如何确定何时以各种方式处理括号,规则相当复杂,实际上在某些情况下编译器不会以预期的方式解析表达式。其中一种情况通俗地称为“最令人烦恼的解析”,其中编译器将对象构造看起来像是函数原型。例如,这段代码:
vector<int> v();
不是否使用默认构造函数创建了一个名为vector<int>
的{{1}}。相反,它将此视为一个名为v
的函数的函数原型,该函数不带参数并生成v
!但是,如果你要写
vector<int>
然后编译器可以明确地推断出这是vector<int> v(10);
传递vector<int>
作为构造函数参数的声明,因为它无法被视为函数原型。规范的§6.8和§8.2通过说任何可以作为声明处理的东西来处理这些情况,并且任何可以被视为函数原型的东西也将如此。
数组上下文中括号的情况(即10
)由不同的逻辑处理,因为在您声明变量或定义类型需要的参数的上下文中明确的括号,你的意图可能没有歧义,因为从上下文中可以清楚地看到你为了声明变量而命名一个类型。
总结 -
T (&array)[N]
和T(value)
形式的投射相同。(T)value
中的括号是为了防止编译器将T (&array)[N]
绑定到&
而不是按照预期绑定到T
。希望这有帮助!
答案 1 :(得分:5)
cast(int)a或int(a)
(int)a是演员
int(a)是一个int的构造,传入一个到int ctor
根据运算符的优先级,arity以及运算符是右关联还是左关联来计算表达式。阅读C ++文本中的运算符优先级图表。
获取程序c ++ decl的副本;它读取C ++表达式并输出表达式的英语语言解释。 Or read this explanation.
答案 2 :(得分:0)
从C ++ 14附录A,完整的列表中的括号可能出现在语法中:
§A.14 Preprocessing directives
control-line: # define identifier lparen identifier-list_opt ) replacement-list new-line
control-line: # define identifier lparen ... ) replacement-list new-line
control-line: # define identifier lparen identifier-list , ... ) replacement-list new-line
§A.2 Lexical conventions
raw-string: " d-char-sequence_opt ( r-char-sequence_opt ) d-char-sequence_opt "
§A.4 Expressions
primary-expression: ( expression )
lambda-declarator: ( parameter-declaration-clause ) mutable_opt exception-specification_opt attribute-specifier-seq_opt trailing-return-type_opt
postfix-expression: const_cast < type-id > ( expression )
postfix-expression: dynamic_cast < type-id > ( expression )
postfix-expression: postfix-expression ( expression-list_opt )
postfix-expression: reinterpret_cast < type-id > ( expression )
postfix-expression: simple-type-specifier ( expression-list_opt )
postfix-expression: static_cast < type-id > ( expression )
postfix-expression: typeid ( expression )
postfix-expression: typeid ( type-id )
postfix-expression: typename-specifier ( expression-list_opt )
unary-expression: alignof ( type-id )
unary-expression: sizeof ( type-id )
unary-expression: sizeof ... ( identifier )
new-expression: ::_opt new new-placement_opt ( type-id ) new-initializer_opt
new-placement: ( expression-list )
new-initializer: ( expression-list_opt )
noexcept-expression: noexcept ( expression )
cast-expression: ( type-id ) cast-expression
§A.5 Statements
selection-statement: if ( condition ) statement
selection-statement: if ( condition ) statement else statement
selection-statement: switch ( condition ) statement
iteration-statement: do statement while ( expression ) ;
iteration-statement: for ( for-init-statement condition_opt ; expression_opt ) statement
iteration-statement: for ( for-range-declaration : for-range-initializer ) statement
iteration-statement: while ( condition ) statement
§A.6 Declarations
static_assert-declaration: static_assert ( constant-expression , string-literal ) ;
decltype-specifier: decltype ( auto )
decltype-specifier: decltype ( expression )
asm-definition: asm ( string-literal ) ;
alignment-specifier: alignas ( assignment-expression ..._opt )
alignment-specifier: alignas ( type-id ..._opt )
attribute-argument-clause: ( balanced-token-seq )
balanced-token: ( balanced-token-seq )
§A.7 Declarators
noptr-declarator: ( ptr-declarator )
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 )
initializer: ( expression-list )
§A.10 Special member functions
mem-initializer: mem-initializer-id ( expression-list_opt )
§A.11 Overloading
operator-function-id: operator ( )
§A.13 Exception handling
handler: catch ( exception-declaration ) compound-statement
dynamic-exception-specification: throw ( type-id-list_opt )
noexcept-specification: noexcept ( constant-expression )
请注意:
if-group
和elif-group
的预处理器规则确实引用了constant-expression
。lparen
表示没有前置空格的(
raw-string
的规则是在lexing期间,因此(
和)
不会成为令牌。在您的问题中,您使用以下内容:
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 )