General topics | ||||||||||||||||
Flow control | ||||||||||||||||
Conditional execution statements | ||||||||||||||||
Iteration statements (loops) | ||||||||||||||||
Jump statements | ||||||||||||||||
Functions | ||||||||||||||||
Function declaration | ||||||||||||||||
Lambda function expression | ||||||||||||||||
inline specifier | ||||||||||||||||
Dynamic exception specifications(until C++17*) | ||||||||||||||||
noexcept specifier(C++11) | ||||||||||||||||
Exceptions | ||||||||||||||||
Namespaces | ||||||||||||||||
Types | ||||||||||||||||
Specifiers | ||||||||||||||||
| ||||||||||||||||
Storage duration specifiers | ||||||||||||||||
Initialization | ||||||||||||||||
Expressions | ||||||||||||||||
Alternative representations | ||||||||||||||||
Literals | ||||||||||||||||
Boolean -Integer -Floating-point | ||||||||||||||||
Character -String -nullptr(C++11) | ||||||||||||||||
User-defined(C++11) | ||||||||||||||||
Utilities | ||||||||||||||||
Attributes(C++11) | ||||||||||||||||
Types | ||||||||||||||||
typedef declaration | ||||||||||||||||
Type alias declaration(C++11) | ||||||||||||||||
Casts | ||||||||||||||||
| ||||||||||||||||
Memory allocation | ||||||||||||||||
Classes | ||||||||||||||||
Class-specific function properties | ||||||||||||||||
| ||||||||||||||||
Special member functions | ||||||||||||||||
Templates | ||||||||||||||||
Miscellaneous | ||||||||||||||||
General | |||||||||||||||||||||
Literals | |||||||||||||||||||||
Operators | |||||||||||||||||||||
Conversions | |||||||||||||||||||||
|
Converts between types using a combination of explicit and implicit conversions.
Contents |
( type-id) unary-expression | (1) | ||||||||
simple-type-specifier( expression-list (optional)) simple-type-specifier ( initializer-list (optional)) | (2) | (until C++11) (since C++11) | |||||||
simple-type-specifier{ initializer-list (optional)} | (3) | (since C++11) | |||||||
simple-type-specifier{ designated-initializer-list} | (4) | (since C++20) | |||||||
typename identifier( initializer-list (optional)) | (5) | (since C++11) | |||||||
typename identifier{ initializer-list (optional)} | (6) | (since C++11) | |||||||
typename identifier{ designated-initializer-list} | (7) | (since C++20) | |||||||
Explicitly converts any number of values to a value of the target type.
type-id | - | atype-id |
unary-expression | - | an unary expression (whose top-level operator does not have aprecedence higher than that of C-style cast) |
simple-type-specifier | - | asimple type specifier |
expression-list | - | a comma-separated list of expressions (except unparenthesizedcomma expressions) |
initializer-list | - | a comma-separated list ofinitializer clauses |
designated-initializer-list | - | a comma-separated list ofdesignated initializer clauses |
identifier | - | a (possibly qualified) identifier (includingtemplate identifiers) |
const_cast
<type-id >(unary-expression );static_cast
<type-id >(unary-expression ), with extensions: pointer or reference to aderived class is additionally allowed to be cast to pointer or reference to unambiguous base class (and vice versa) even if the base class isinaccessible (that is, this cast ignores the private inheritance specifier). Same applies to castingpointer to member to pointer to member of unambiguous non-virtual base;reinterpret_cast
<type-id >(unary-expression );T
, which is determined from the specified type and initializer(since C++17):
| (until C++17) | ||
| (since C++17) |
T
is (possibly cv-qualified)void, the result isan rvalue(until C++11)a prvalue(since C++11) of typevoid that performs no initialization.
| (until C++11) |
| (since C++11) |
T
is a reference type, the function-style cast has the same effect asdirect-initializing an invented variablet of typeT
from the specified initializer, and the result is the initializedt.
| (until C++11) |
| (since C++11) |
T
designating a temporary(until C++17)whose result object is(since C++17)direct-initialized with the specified initializer.In the case of an ambiguity between an expression statement with a function-style cast expression as its leftmost subexpression and a declaration statement, the ambiguity is resolved by treating it as a declaration. This disambiguation is purely syntactic: it does not consider the meaning of names occurring in the statement other than whether they are type names:
struct M{};struct L{ L(M&);}; M n;void f(){ M(m);// declaration, equivalent to M m; L(n);// ill-formed declaration, equivalent to L n; L(l)(m);// still a declaration, equivalent to L l((m));}
However, if the outermost declarator in the ambiguous declaration statement has atrailing return type, the statement will only be treated as a declaration statement if the trailing return type starts withauto: struct M; struct S{ S* operator()();int N;int M; void mem(S s){auto(s)()->M;// expression (S::M hides ::M), invalid before C++23}}; void f(S s){{auto(s)()->N;// expression, invalid before C++23auto(s)()->M;// function declaration, equivalent to M s();}{ S(s)()->N;// expression S(s)()->M;// expression}} | (since C++11) |
The ambiguity above can also occur in the context of a declaration. In that context, the choice is between an object declaration with a function-style cast as the initializer and a declaration involving a function declarator with a redundant set of parentheses around a parameter name. The resolution is also to consider any construct, such as the potential parameter declaration, that could possibly be a declaration to be a declaration:
struct S{ S(int);}; void foo(double a){ S w(int(a));// function declaration: has a parameter `a` of type int S x(int());// function declaration: has an unnamed parameter of type int(*)()// that is adjusted from int() // Ways to avoid ambiguity: S y((int(a)));// object declaration: extra pair of parentheses S y((int)a);// object declaration: C-style cast S z=int(a);// object declaration: no ambiguity for this syntax}
However, if the outermost declarator in the ambiguous parameter declaration has atrailing return type, the ambiguity will only be resolved by treating it as a declaration if it starts withauto: typedefstruct BB{int C[2];}*B, C; void foo(){ S a(B()->C);// object declaration: B()->C cannot declare a parameter S b(auto()->C);// function declaration: has an unnamed parameter of type C(*)()// that is adjusted from C()} | (since C++11) |
An ambiguity can arise from the similarity between a function-style cast and atype-id. The resolution is that any construct that could possibly be a type-id in its syntactic context shall be considered a type-id:
// `int()` and `int(unsigned(a))` can both be parsed as type-id:// `int()` represents a function returning int// and taking no argument// `int(unsigned(a))` represents a function returning int// and taking an argument of type unsignedvoid foo(signedchar a){ sizeof(int());// type-id (ill-formed) sizeof(int(a));// expression sizeof(int(unsigned(a)));// type-id (ill-formed) (int())+1;// type-id (ill-formed)(int(a))+1;// expression(int(unsigned(a)))+1;// type-id (ill-formed)}
However, if the outermostabstract-declarator in the ambiguoustype-id has atrailing return type, the ambiguity will only be resolved by treating it as a type-id if it starts withauto: typedefstruct BB{int C[2];}*B, C; void foo(){ sizeof(B()->C[1]);// OK, sizeof(expression) sizeof(auto()->C[1]);// error: sizeof of a function returning an array} | (since C++11) |
Feature-test macro | Value | Std | Feature |
---|---|---|---|
__cpp_auto_cast | 202110L | (C++23) | auto(x) andauto{x} |
#include <cassert>#include <iostream> double f=3.14;unsignedint n1=(unsignedint)f;// C-style castunsignedint n2=unsigned(f);// function-style cast class C1;class C2;C2* foo(C1* p){return(C2*)p;// casts incomplete type to incomplete type} void cpp23_decay_copy_demo(){auto inc_print=[](int& x,constint& y){++x;std::cout<<"x:"<< x<<", y:"<< y<<'\n';}; int p{1}; inc_print(p, p);// prints x:2 y:2, because param y here is an alias of pint q{1}; inc_print(q,auto{q});// prints x:2 y:1, auto{q} (C++23) casts to prvalue,// so the param y is a copy of q (not an alias of q)} // In this example, C-style cast is interpreted as static_cast// even though it would work as reinterpret_caststruct A{};struct I1: A{};struct I2: A{};struct D: I1, I2{}; int main(){ D* d= nullptr;// A* a = (A*)d; // compile-time error A* a=reinterpret_cast<A*>(d);// this compilesassert(a== nullptr); cpp23_decay_copy_demo();}
Output:
x:2 y:2x:2 y:1
The following behavior-changing defect reports were applied retroactively to previously published C++ standards.
DR | Applied to | Behavior as published | Correct behavior |
---|---|---|---|
CWG 1223 (P2915R0) | C++11 | the addition of trailing return type introduced more ambiguities | resolves them |
CWG 1893 | C++11 | function-style cast did not consider pack expansions | considers them |
CWG 2351 | C++11 | void{} was ill-formed | made well-formed |
CWG 2620 | C++98 | the resolution of ambiguous function parameters might be misinterpreted | improved the wording |
CWG 2828 | C++98 | a C-style cast was ill-formed if multiple interpretations of astatic_cast followed by aconst_cast exist, regardless of whether these conversions are actually used | only considers the conversions possibly being used |
CWG 2894 | C++98 | function-style casts could create reference rvalues | can only create reference lvalues |
const_cast conversion | adds or removes const[edit] |
static_cast conversion | performs basic conversions[edit] |
dynamic_cast conversion | performs checked polymorphic conversions[edit] |
reinterpret_cast conversion | performs general low-level conversions[edit] |
standard conversions | implicit conversions from one type to another[edit] |
C documentation forcast operator |