Namespaces
Variants

Explicit type conversion

From cppreference.net
C++ language
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
constexpr (C++11)
consteval (C++20)
constinit (C++20)
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

명시적 변환과 암시적 변환의 조합을 사용하여 타입 간 변환을 수행합니다.

목차

구문

( type-id ) unary-expression (1)
simple-type-specifier ( expression-list  (선택적) )
simple-type-specifier ( initializer-list  (선택적) )
(2) (C++11 이전)
(C++11 이후)
simple-type-specifier { initializer-list  (선택적) } (3) (C++11 이후)
simple-type-specifier { designated-initializer-list } (4) (C++20 이후)
typename identifier ( initializer-list  (선택적) ) (5) (C++11 이후)
typename identifier { initializer-list  (선택적) } (6) (C++11 이후)
typename identifier { designated-initializer-list } (7) (C++20 이후)

임의 개수의 값을 대상 타입의 값으로 명시적으로 변환합니다.

1) 명시적 타입 변환(캐스트 표기법), C-스타일 캐스트 라고도 함.
2-7) 명시적 타입 변환(함수 표기법), function-style cast 라고도 함.
type-id - 타입 식별자
unary-expression - 단항 표현식 (최상위 연산자의 우선순위 가 C-스타일 캐스트보다 높지 않은)
simple-type-specifier - 단순 타입 지정자
expression-list - 쉼표로 구분된 표현식 목록 (괄호로 묶이지 않은 쉼표 표현식 제외)
initializer-list - 쉼표로 구분된 초기화 절 목록
designated-initializer-list - 쉼표로 구분된 지정 초기화 절 목록
identifier - (한정자가 있을 수 있는) 식별자 ( 템플릿 식별자 포함)

설명

1) C-스타일 캐스트가 발견되면, 컴파일러는 다음 캐스트 표현식 순서로 해석을 시도합니다:
a) const_cast < type-id  > ( unary-expression  ) ;
b) static_cast < type-id  > ( unary-expression  ) , 확장 사항: 파생 클래스 에 대한 포인터나 참조는 명확한 기본 클래스에 대한 포인터나 참조로 추가적으로 캐스트가 허용됩니다(그 반대의 경우도 마찬가지). 기본 클래스가 접근 불가 한 경우에도 가능합니다(즉, 이 캐스트는 private 상속 지정자를 무시합니다). 동일한 규칙이 명확한 비가상 기본 클래스의 멤버에 대한 포인터로 멤버 포인터 를 캐스트하는 경우에도 적용됩니다;
c) a static_cast (확장 기능 포함) 다음에 const_cast 가 오는 경우;
d) reinterpret_cast < type-id  > ( unary-expression  ) ;
e) a reinterpret_cast 다음에 const_cast 가 오는 경우.
각각의 캐스트 연산자 요구사항을 만족하는 첫 번째 선택지가 선택됩니다. 해당 변환이 잘못된 형식이더라도 선택됩니다(예제 참조). 만약 static_cast 뒤에 const_cast 가 사용되고, 이러한 변환이 여러 방식으로 해석될 수 있는 경우, 해당 변환은 잘못된 형식입니다.
또한, C-스타일 캐스트는 불완전 클래스 타입에 대한 포인터로부터, 그리고 그 사이에서 캐스트할 수 있습니다. 만약 type-id unary-expression 의 타입이 모두 불완전 클래스 타입에 대한 포인터라면, static_cast 또는 reinterpret_cast 중 어느 것이 선택되는지는 명시되어 있지 않습니다.
2-7) 함수 스타일 캐스트는 타입 ( simple-type-specifier  또는 identifier  (C++11부터) )과 초기화자 (나머지 부분)를 지정하며, 대상 타입 T 의 값을 생성합니다. 이때 T 는 지정된 타입 및 초기화자로부터 결정됩니다 (C++17부터) :

T 는 지정된 타입입니다.

(C++17 이전)

T 는 다음과 같이 결정됩니다:

  • 지정된 타입이 추론된 클래스 타입을 위한 자리 표시자(placeholder)인 경우, T 클래스 템플릿 인수 추론 에 대해 오버로드 해결로 선택된 함수의 반환 타입입니다.
(C++23부터)
  • 그 외의 경우, T 는 지정된 타입입니다.
(C++17부터)
변환 결과는 다음과 같이 결정됩니다:
  • 함수 스타일 캐스트가 구문 (2) 에 해당하고, 괄호 안에 정확히 하나의 표현식이 있는 경우, 이 캐스트는 해당 C 스타일 캐스트와 동일합니다.
  • 그렇지 않고 T 가 (possibly cv-qualified) void 인 경우, 결과는 초기화를 수행하지 않는 rvalue (until C++11) prvalue (since C++11) 입니다.
  • 초기화자가 ( ) 가 아닌 경우, 프로그램은 ill-formed입니다.
(until C++11)
  • 초기화자가 ( ) 또는 { } 가 아닌 경우 ( pack expansion 후에), 프로그램은 ill-formed입니다.
(since C++11)
  • 그렇지 않고 T 가 참조 타입인 경우, 함수 스타일 캐스트는 direct-initializing 으로 생성된 변수 t T 타입으로 지정된 초기화자로 초기화하는 것과 동일한 효과를 가지며, 결과는 초기화된 t 입니다.
  • 결과는 lvalue입니다.
(until C++11)
  • T 가 lvalue 참조 타입이거나 함수 타입에 대한 rvalue 참조인 경우, 결과는 lvalue입니다.
  • 그렇지 않으면 결과는 xvalue입니다.
(since C++11)
  • 그렇지 않으면, 결과는 rvalue (until C++11) prvalue (since C++11) 입니다. 임시 객체를 지정하는 (until C++17) 결과 객체가 (since C++17) direct-initialized T 타입의 값입니다.

모호성 해결

모호한 선언문

함수 스타일 캐스트 표현식을 가장 왼쪽 부분표현식으로 갖는 표현식 문과 선언 문 사이에 모호성이 발생하는 경우, 이를 선언으로 취급하여 모호성을 해결합니다. 이 모호성 해소는 순전히 구문적입니다: 문장에서 발생하는 이름들의 의미는 고려하지 않고, 해당 이름들이 타입 이름인지 여부만을 고려합니다:

struct M {};
struct L { L(M&); };
M n;
void f()
{
    M(m);    // 선언, M m;과 동등함
    L(n);    // 잘못된 선언, L n;과 동등함
    L(l)(m); // 여전히 선언, L l((m));과 동등함
}

그러나 모호한 선언문에서 가장 바깥쪽 선언자가 후행 반환 타입 을 가지고 있는 경우, 후행 반환 타입이 auto 로 시작할 때만 해당 문장이 선언문으로 처리됩니다:

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++23
        auto(s)()->M; // function declaration, equivalent to M s();
    }
    {
        S(s)()->N;    // expression
        S(s)()->M;    // expression
    }
}
(C++11부터)

모호한 함수 매개변수

위의 모호성은 선언 문맥에서도 발생할 수 있습니다. 해당 문맥에서 선택은 함수 형식 캐스트를 초기화자로 갖는 객체 선언과, 매개변수 이름을 둘러싼 중복된 괄호 집합을 가진 함수 선언자를 포함하는 선언 사이에 있습니다. 해결 방법 또한 잠재적 매개변수 선언과 같은 모든 구문을 선언일 가능성이 있는 경우 선언으로 간주하는 것입니다:

struct S
{
    S(int);
};
void foo(double a)
{
    S w(int(a)); // 함수 선언: int 타입의 매개변수 `a`를 가짐
    S x(int());  // 함수 선언: int(*)() 타입의 이름 없는 매개변수를 가짐
                 // int()에서 조정됨
    // 모호함을 피하는 방법들:
    S y((int(a))); // 객체 선언: 추가 괄호 쌍
    S y((int)a);   // 객체 선언: C-스타일 캐스트
    S z = int(a);  // 객체 선언: 이 구문에서는 모호함이 없음
}

그러나 모호한 매개변수 선언에서 가장 바깥쪽 선언자가 후행 반환 타입 을 가지고 있다면, 이 모호성은 선언이 auto 로 시작하는 경우에만 선언으로 처리하여 해결됩니다:

typedef struct BB { int C[2]; } *B, C;
void foo()
{
    S a(B()->C);    // 객체 선언: B()->C는 매개변수를 선언할 수 없음
    S b(auto()->C); // 함수 선언: C(*)() 타입의 이름 없는 매개변수를 가짐
                    // C()에서 조정됨
}
(C++11부터)

모호한 타입 식별자

함수 스타일 캐스트와 type-id 간의 유사성으로 인해 모호성이 발생할 수 있습니다. 해결 방법은 구문적 맥락에서 type-id가 될 수 있는 모든 구문은 type-id로 간주되어야 한다는 것입니다:

// `int()`와 `int(unsigned(a))`는 모두 type-id로 파싱될 수 있습니다:
// `int()`            int를 반환하고 인수를 받지 않는 함수를 나타냅니다
// `int(unsigned(a))` int를 반환하고 unsigned 타입의 인수를 받는 함수를 나타냅니다
void foo(signed char a)
{
    sizeof(int());            // type-id (잘못된 형식)
    sizeof(int(a));           // expression
    sizeof(int(unsigned(a))); // type-id (잘못된 형식)
    (int()) + 1;            // type-id (잘못된 형식)
    (int(a)) + 1;           // expression
    (int(unsigned(a))) + 1; // type-id (잘못된 형식)
}

그러나 모호한 type-id 에서 가장 바깥쪽 abstract-declarator trailing return type 을 가지고 있다면, 이 모호성은 auto 로 시작하는 경우에만 type-id로 처리하여 해결됩니다:

typedef struct 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)

참고 사항

기능 테스트 매크로 표준 기능
__cpp_auto_cast 202110L (C++23) auto ( x ) auto { x }

예제

#include <cassert>
#include <iostream>
double f = 3.14;
unsigned int n1 = (unsigned int)f; // C-스타일 캐스트
unsigned int n2 = unsigned(f);     // 함수-스타일 캐스트
class C1;
class C2;
C2* foo(C1* p)
{
    return (C2*)p; // 불완전 타입을 불완전 타입으로 캐스트
}
void cpp23_decay_copy_demo()
{
    auto inc_print = [](int& x, const int& y)
    {
        ++x;
        std::cout << "x:" << x << ", y:" << y << '\n';
    };
    int p{1};
    inc_print(p, p); // x:2 y:2 출력, 여기서 매개변수 y는 p의 별칭이기 때문
    int q{1};
    inc_print(q, auto{q}); // x:2 y:1 출력, auto{q} (C++23)는 prvalue로 캐스트되므로,
                           // 매개변수 y는 q의 복사본임(q의 별칭이 아님)
}
// 이 예제에서 C-스타일 캐스트는 reinterpret_cast로 동작할 수 있음에도
// static_cast로 해석됨
struct A {};
struct I1 : A {};
struct I2 : A {};
struct D : I1, I2 {};
int main()
{
    D* d = nullptr;
//  A* a = (A*)d;                   // 컴파일 타임 오류
    A* a = reinterpret_cast<A*>(d); // 이 코드는 컴파일됨
    assert(a == nullptr);
    cpp23_decay_copy_demo();
}

출력:

x:2 y:2
x:2 y:1

결함 보고서

다음의 동작 변경 결함 보고서들은 이전에 발표된 C++ 표준에 소급 적용되었습니다.

DR 적용 대상 게시된 동작 올바른 동작
CWG 1223
( P2915R0 )
C++11 후행 반환 타입 추가로 더 많은 모호성이 발생함 해당 모호성을 해결함
CWG 1893 C++11 함수 스타일 캐스트가 팩 확장을 고려하지 않음 팩 확장을 고려함
CWG 2351 C++11 void { } 가 잘못된 형식이었음 올바른 형식으로 변경됨
CWG 2620 C++98 모호한 함수 매개변수의 해결이
오해될 수 있었음
문구를 개선함
CWG 2828 C++98 C-스타일 캐스트는 static_cast 뒤에 const_cast 가 오는
여러 해석이 존재할 경우 잘못된 형식이었으며,
이러한 변환이 실제로 사용되는지와 관계없이 적용됨
실제로 사용될 수 있는
변환만
고려함
CWG 2894 C++98 함수 스타일 캐스트가 참조 우측값을 생성할 수 있었음 참조 좌측값만 생성할 수 있음

참조문헌

  • C++23 표준 (ISO/IEC 14882:2024):
  • 7.6.1.4 명시적 타입 변환 (함수 표기법) [expr.type.conv]
  • 7.6.3 명시적 타입 변환 (캐스트 표기법) [expr.cast]
  • C++20 표준(ISO/IEC 14882:2020):
  • 7.6.1.4 명시적 타입 변환 (함수 표기법) [expr.type.conv]
  • 7.6.3 명시적 타입 변환 (캐스트 표기법) [expr.cast]
  • C++17 표준(ISO/IEC 14882:2017):
  • 8.2.3 명시적 타입 변환(함수 표기법) [expr.type.conv]
  • 8.4 명시적 타입 변환(캐스트 표기법) [expr.cast]
  • C++14 표준(ISO/IEC 14882:2014):
  • 5.2.3 명시적 타입 변환 (함수 표기법) [expr.type.conv]
  • 5.4 명시적 타입 변환 (캐스트 표기법) [expr.cast]
  • C++11 표준 (ISO/IEC 14882:2011):
  • 5.2.3 명시적 타입 변환 (함수 표기법) [expr.type.conv]
  • 5.4 명시적 타입 변환 (캐스트 표기법) [expr.cast]
  • C++03 표준(ISO/IEC 14882:2003):
  • 5.2.3 명시적 타입 변환 (함수 표기법) [expr.type.conv]
  • 5.4 명시적 타입 변환 (캐스트 표기법) [expr.cast]
  • C++98 표준(ISO/IEC 14882:1998):
  • 5.2.3 명시적 타입 변환 (함수 표기법) [expr.type.conv]
  • 5.4 명시적 타입 변환 (캐스트 표기법) [expr.cast]

참고 항목

const_cast conversion const 추가 또는 제거
static_cast conversion 기본 변환 수행
dynamic_cast conversion 검증된 다형적 변환 수행
reinterpret_cast conversion 일반적인 저수준 변환 수행
standard conversions 한 타입에서 다른 타입으로의 암시적 변환
C documentation for cast operator