Expressions[Expr]

5 Expressions[Expr]

This chapter defines the formulations of expressions and the behavior of operators when they are not overloaded. Only member operators may be overloaded1. Operator overloading does not alter the rules for operators defined by this standard.

An expression may also be an unevaluated operand when it appears in some contexts. An unevaluated operand is a expression which is not evaluated in the program2.

Whenever a glvalue appears in an expression that expects a prvalue, a standard conversion sequence is applied based on the rules in 4.

5.1 Usual Arithmetic Conversions[Expr.conv]

Binary operators for arithmetic and enumeration type require that both operands are of a common type. When the types do not match the usual arithmetic conversions are applied to yield a common type. When usual arithmetic conversions are applied to vector operands they behave as component-wise conversions (4.14). The usual arithmetic conversions are:

  • If either operand is of scoped enumeration type no conversion is performed, and the expression is ill-formed if the types do not match.

  • If either operand is a vector<T,X>, vector truncation or scalar extension is performed with the following rules:

    • If both vectors are of the same length, no dimension conversion is required.

    • If one operand is a vector and the other operand is a scalar, the scalar is extended to a vector via a Splat conversion (4.10) to match the length of the vector.

    • Otherwise, if both operands are vectors of different lengths, the vector of longer length is truncated to match the length of the shorter vector (4.13).

  • If either operand is of type double or vector<double, X>, the other operator shall be converted to match.

  • Otherwise, if either operand is of type float or vector<float, X>, the other operand shall be converted to match.

  • Otherwise, if either operand is of type half or vector<half, X>, the other operand shall be converted to match.

  • Otherwise, integer promotions are performed on each scalar or vector operand following the appropriate scalar or component-wise conversion (4).

    • If both operands are scalar or vector elements of signed or unsigned types, the operand of lesser integer conversion rank shall be converted to the type of the operand with greater rank.

    • Otherwise, if both the operand of unsigned scalar or vector element type is of greater rank than the operand of signed scalar or vector element type, the signed operand is converted to the type of the unsigned operand.

    • Otherwise, if the operand of signed scalar or vector element type is able to represent all values of the operand of unsigned scalar or vector element type, the unsigned operand is converted to the type of the signed operand.

    • Otherwise, both operands are converted to a scalar or vector type of the unsigned integer type corresponding to the type of the operand with signed integer scalar or vector element type.

5.2 Primary Expressions[Expr.Primary]

primary-expression:
literal
this
( expression )
id-expression

5.2.1 Literals[Expr.Primary.Literal]

The type of a literal is determined based on the grammar forms specified in 2.9.1.

5.2.2 This[Expr.Primary.This]

The keyword this names a reference to the implicit object of non-static member functions. The this parameter is always a prvalue of non-cv-qualifiedtype. 3

A this expression shall not appear outside the declaration of a non-static member function.

5.2.3 Parenthesis[Expr.Primary.Paren]

An expression (E) enclosed in parenthesis has the same type, result and value category as E without the enclosing parenthesis. A parenthesized expression may be used in the same contexts with the same meaning as the same non-parenthesized expression.

5.2.4 Names[Expr.Primary.ID]

The grammar and behaviors of this section are almost identical to C/C++ with some subtractions (notably lambdas and destructors).

id-expression:
unqualified-id
qualified-id

5.2.4.1 Unqualified Identifiers[Expr.Primary.ID.Unqual]

unqualified-id:
identifier
operator-function-id
conversion-function-id
template-id

5.2.4.2 Qualified Identifiers[Expr.Primary.ID.Qual]

qualified-id:
nested-name-specifier templateopt unqualified-id
nested-name-specifier:
::
type-name ::
namespace-name ::
nested-name-specifier identifier ::
nested-name-specifier templateopt simple-template-id ::

5.3 Postfix Expressions[Expr.Post]

postfix-expression:
primary-expression
postfix-expression [ expression ]
postfix-expression [ braced-init-list ]
postfix-expression ( expression-listopt )
simple-type-specifier ( expression-listopt )
typename-specifier ( expressionopt )
simple-type-specifier braced-init-list
typename-specifier braced-init-list
postfix-expression . templateopt id-expression
postfix-expression . vector-swizzle-component-sequence
postfix-expression . matrix-swizzle-component-sequence
postfix-expression ++
postfix-expression

5.4 Subscript[Expr.Post.Subscript]

A postfix-expression followed by an expression in square brackets () is a subscript expression. In an array subscript expression of the form E1[E2], E1 must either be a variable of array, vector, or matrix of T[], or an object of type T where T provides an overloaded implementation of operator[] (8).4

If the postfix expression E1 is of vector type, the expression E2 must be a value of integer type. If the value is known at compile time to be outside the range where N is the number of elements in the vector, the program is ill-formed. If the value is outside the range at runtime, the behavior is undefined.

5.5 Swizzle Expressions[Expr.Post.Swizzle]

A postfix-expression followed by a dot (.) and a sequence of one or more swizzle components is a postfix expression. The postfix expression before the dot is evaluated and must be of vector or matrix type. If the postfix expression before the dot is an lvalue, the swizzle expression may produce either an lvalue or a prvalue; otherwise it produces a prvalue.

If the postfix expression before the dot is an lvalue and the swizzle-component-sequence contains no repeated components, the swizzle expression is an lvalue; otherwise it is a prvalue.

5.5.1 Vector Swizzle[Expr.Post.Swizzle.Vector]

vector-swizzle-component-sequence:
swizzle-component-sequence-rgba
swizzle-component-sequence-xyzw
swizzle-component-sequence-rgba:
swizzle-component-rgba
swizzle-component-sequence-rgba swizzle-component-rgba
swizzle-component-sequence-xyzw:
swizzle-component-xyzw
swizzle-component-sequence-xyzw swizzle-component-xyzw
swizzle-component-rgba: one of
r g b a
swizzle-component-xyzw: one of
x y z w

A vector-swizzle-component-sequence is a sequence of one or more swizzle components of either the swizzle-component-rgba or swizzle-component-xyzw forms; the two forms may not be mixed in the same vector-swizzle-component-sequence. The type of a swizzle expression is a vector of the same element type as the postfix expression before the dot, with a number of elements equal to the number of components in the vector-swizzle-component-sequence.

Vector swizzle components map to elements of the vector in the following way:

Element Index RGBA component XYZW component
0 r x
1 g y
2 b z
3 a w

A program is ill-formed if any component in the swizzle-component-sequence refers to an element index that is out of range of the vector type of the postfix expression before the dot.

5.5.2 Matrix Swizzle[Expr.Post.Swizzle.Matrix]

matrix-swizzle-component-sequence:
matrix-zero-indexed-swizzle-sequence
matrix-one-indexed-swizzle-sequence
matrix-zero-indexed-swizzle-sequence:
matrix-zero-indexed-swizzle
matrix-zero-indexed-swizzle-sequence matrix-zero-indexed-swizzle
matrix-zero-indexed-swizzle:
_m zero-index-value zero-index-value
zero-index-value: one of
1 2 3
matrix-one-indexed-swizzle-sequence:
matrix-one-indexed-swizzle
matrix-one-indexed-swizzle-sequence matrix-one-indexed-swizzle
matrix-one-indexed-swizzle:
_ one-index-value one-index-value
one-index-value: one of
2 3 4

  • ._ (math-style): subsequent subscripts use 1-based indexing for both row and column.

  • ._m (memory-style): subsequent subscripts use 0-based indexing for both row and column.

A matrix-swizzle-component-sequence is a sequence of one but less than or equal to four swizzle components of either the matrix-zero-indexed-swizzle or matrix-one-indexed-swizzle forms; the two forms may not be mixed in the same matrix-swizzle-component-sequence. The type of a swizzle expression is a vector of the same element type as the postfix expression before the dot, with a number of elements equal to the number of components in the matrix-swizzle-component-sequence.

Matrix swizzle components map to elements of the matrix in the following way:

Element Index 0 indexed component 1 indexed component
0,0 _m00 _11
0,1 _m01 _12
0,2 _m02 _13
0,3 _m03 _14
1,0 _m10 _21
1,1 _m11 _22
1,2 _m12 _23
1,3 _m13 _24
2,0 _m20 _31
2,1 _m21 _32
2,2 _m22 _33
2,3 _m23 _34
3,0 _m30 _41
3,1 _m31 _42
3,2 _m32 _43
3,3 _m33 _44

5.6 Function Calls[Expr.Post.Call]

A function call may be an ordinary function, or a member function. In a function call to an ordinary function, the postfix-expression must be an lvalue that refers to a function. In a function call to a member function, the postfix-expression will be an implicit or explicit class member access whose id-expression is a member function name.

When a function is called, each parameter shall be initialized with its corresponding argument. The order in which parameters are initialized is unspecified. 5

If the function is a non-static member function the this argument shall be initialized to a reference to the object of the call as if casted by an explicit cast expression to an lvalue reference of the type that the function is declared as a member of.

Parameters are either input parameters, output parameters, or input/output parameters as denoted in the called function’s declaration (7.5). For all types of parameters the argument expressions are evaluated before the function call occurs.

Input parameters are passed by-value into a function. If an argument to an input parameter is of constant-sized array type, the array is copied to a temporary and the temporary value is converted to an address via array-to-pointer decay. If an argument is an unsized array type, the array lvalue directly decays via array-to-pointer decay. 6

Arguments to output and input/output parameters must be lvalues. Output parameters are not initialized prior to the call; they are passed as an uninitialized cxvalue (3.10). An output parameter is only initialized explicitly inside the called function. It is undefined behavior to not explicitly initialize an output parameter before returning from the function in which it is defined. The cxvalue created from an argument to an input/output parameter is initialized through copy-initialization from the lvalue argument expression. Overload resolution shall occur on argument initialization as if the expression T Param = Arg were evaluated. In both cases, the cxvalue shall have the type of the parameter and the argument can be converted to that type through implicit or explicit conversion.

If an argument to an output or input/output parameter is a constant sized array, the array is copied to a temporary cxvalue following the same rules for any other data type. If an argument to an output or input/output parameter is an unsized array type, the array lvalue directly decays via array-to-pointer decay. An argument of a constant sized array of type T[N] can be converted to a cxvalue of an unsized array of type T[] through array to pointer decay. An unsized array of type T[], cannot be implicitly converted to a a constant sized array of type T[N].

On expiration of the cxvalue, the value is assigned back to the argument lvalue expression using a resolved assignment expression as if the expression Arg = Param were written7. The argument expression must be of a type or able to convert to a type that has defined copy-initialization to and assignment from the parameter type. The lifetime of the cxvalue begins at argument expression evaluation, and ends after the function returns. A cxvalue argument is passed by-address to the caller.

If the lvalue passed to an output or input/output parameter does not alias any other parameter passed to that function, an implementation may avoid the creation of excess temporaries by passing the address of the lvalue instead of creating the cxvalue.

When a function is called, any parameter of object type must have completely defined type, and any parameter of array of object type must have completely defined element type.8 The lifetime of a parameter ends on return of the function in which it is defined.9 Initialization and destruction of each parameter occurs within the context of the calling function.

The value of a function call is the value returned by the called function.

A function call is an lvalue if the result type is an lvalue reference type; otherwise it is a prvalue.

If a function call is a prvalue of object type, the type of the prvalue must be complete.