Namespaces
Variants

static_cast 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

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

목차

구문

static_cast< target-type  >( expression  )

target-type 타입의 값을 반환합니다.

설명

다음 변환들만 static_cast 를 사용하여 수행할 수 있으며, 이러한 변환이 constness 제거 (또는 volatility 제거)를 유발하는 경우는 예외입니다.

1) 만약 expression 이 " cv1 Base " 타입의 lvalue이고 target-type 이 "참조 cv2 Derived "인 경우, 다음 조건들이 모두 만족되면 결과는 expression 을 포함하는 Derived 타입 객체를 참조합니다:
  • Derived 는 완전한 클래스 타입입니다.
  • Base Derived 의 기본 클래스입니다.
  • cv1 cv2 보다 더 큰 cv-한정자를 가지지 않습니다.
다음 조건 중 하나라도 만족되면 프로그램은 잘못 형성됩니다:
  • Base Derived 가상 기본 클래스 인 경우.
  • Base Derived 의 가상 기본 클래스의 기본 클래스인 경우.
  • "pointer to Derived "에서 "pointer to Base "로의 유효한 표준 변환 이 존재하지 않는 경우.
만약 expression 이 실제로 Derived 타입 객체의 기본 클래스 하위 객체가 아닌 경우, 동작은 정의되지 않습니다.
struct B {};
struct D : B { B b; };
D d;
B& br1 = d;
B& br2 = d.b;
static_cast<D&>(br1); // OK, lvalue denoting the original “d” object
static_cast<D&>(br2); // UB: the “b” subobject is not a base class subobject
2) target-type 이 " Derived 에 대한 rvalue 참조"이고 expression 이 "(possibly cv-qualified) Base " 타입의 xvalue이며 Base Derived 의 기본 클래스인 경우, 이러한 변환의 결과와 제약 조건은 " Base lvalue에서 Derived 참조" 변환과 동일합니다.
3) target-type 이 rvalue 참조 타입이고 참조된 타입이 expression 의 타입과 reference-compatible 한 경우, static_cast glvalue, class prvalue, 또는 array prvalue (until C++17) 모든 lvalue (since C++17) expression 의 값을 해당 표현식과 동일한 객체를 참조하는 xvalue로, 또는 해당 기본 클래스 하위 객체로 변환합니다( target-type 에 따라 다름). [1]
target-type expression 의 타입에 대한 접근 불가능하거나 모호한 기본 클래스인 경우, 프로그램은 ill-formed입니다.
expression bit-field lvalue인 경우, 먼저 기본 타입의 prvalue로 변환됩니다.
(since C++11)
4) 만약 target-type 이 (cv-qualified일 수 있는) void 인 경우, 변환은 결과를 생성하지 않습니다. 이 경우 expression 폐기 값 표현식(discarded-value expression) 입니다.
5) 그렇지 않으면, expression 은 다음 조건이 충족될 경우 target-type 으로 명시적으로 변환될 수 있습니다:

선언문 target-type temp ( expression  ) ; 이 어떤 임시 변수 temp 에 대해 올바른 형식일 때.

이러한 명시적 변환의 효과는 선언 및 초기화를 수행한 후 temp 를 변환 결과로 사용하는 것과 동일합니다. expression 은 초기화가 이를 lvalue (C++11까지) glvalue (C++11부터) 로 사용하는 경우에만 lvalue (C++11까지) glvalue (C++11부터) 로 사용됩니다.

(C++17까지)

다음 조건 중 하나가 충족될 때:

  • expression 에서 target-type 으로의 암시적 변환 시퀀스가 존재합니다.
  • expression 으로부터 target-type 타입의 객체 또는 참조자를 직접 초기화 하기 위한 오버로드 해결 에서 최소한 하나의 유효한 함수를 찾을 수 있습니다.
  • target-type 가 첫 번째 요소 x 를 갖는 집계 타입 이고, expression 에서 x 의 타입으로의 암시적 변환 시퀀스가 존재합니다.
(C++20부터)

명시적 변환은 다음과 같이 정의됩니다:

  • target-type 이 참조 타입인 경우, 그 효과는 어떤 임시 변수 temp 에 대해 선언 및 초기화 target-type temp ( expression  ) ; 를 수행한 후 temp 를 변환 결과로 사용하는 것과 동일합니다.
  • 그렇지 않으면, 결과 객체는 expression 으로부터 직접 초기화됩니다.
(C++17부터)
6) 그렇지 않고, expression 에서 target-type 로의 변환이 표준 변환 순서의 역변환이고, 다음 변환들 중 어느 것도 포함하지 않는 경우, 변환은 static_cast 로 수행될 수 있습니다:
(C++17부터)
프로그램이 잘못된 표준 변환 순서의 역변환을 수행하기 위해 static_cast 를 사용하는 경우, 이는 잘못된 형식입니다.
7) 그 외의 경우, lvalue-to-rvalue, array-to-pointer, 그리고 function-to-pointer 변환이 expression 에 적용됩니다. 이러한 변환 후에, static_cast 에 의해 수행될 수 있는 변환은 다음과 같습니다:
a) 범위 있는 열거형 타입의 값은 정수 또는 부동소수점 타입으로 변환될 수 있습니다.
  • 만약 target-type 이 (possibly cv-qualified) bool 인 경우, 결과는 expression 의 원래 값이 0이면 false 이고 다른 모든 값에 대해서는 true 입니다.
  • 만약 target-type 이 (possibly cv-qualified) bool 이 아닌 정수 타입인 경우, expression 의 원래 값이 target-type 으로 표현 가능하면 값은 변경되지 않습니다. 그렇지 않으면 결과 값은 지정되지 않습니다.
(C++20 이전)
  • 만약 target-type 이 정수 타입인 경우, 결과는 열거형의 기반 타입으로 변환한 후 target-type 으로 변환하는 것과 동일합니다.
(C++20 이후)
  • 만약 target-type 이 부동소수점 타입인 경우, 결과는 원래 값에서 target-type 으로 변환하는 것과 동일합니다.
(C++11 이후)
b) 정수 또는 열거형 타입의 값은 모든 완전한 열거형 타입으로 변환될 수 있습니다.
  • 만약 target-type 이 고정된 기반 타입을 가지고 있다면, expression 은 먼저 integral promotion 또는 integral conversion 을 통해 해당 타입으로 변환된 후, 필요하다면 target-type 으로 변환됩니다.
  • 만약 target-type 이 고정된 기반 타입을 가지고 있지 않다면, 원래 값이 열거형 값의 범위 내에 있는 경우 expression 의 값은 변경되지 않으며, 그렇지 않은 경우 동작은 정의되지 않습니다.
c) 부동 소수점 타입의 값은 완전한 열거형 타입으로도 변환될 수 있습니다. 결과는 expression 의 원래 값을 먼저 target-type 의 기반 타입으로 변환 한 다음, target-type 자체로 변환한 것과 동일합니다.
d) 부동소수점 타입의 prvalue는 명시적으로 다른 부동소수점 타입으로 변환될 수 있습니다.
  • expression 의 원본 값이 target-type 에서 정확히 표현 가능한 경우, 값은 변경되지 않습니다.
  • 그렇지 않고 expression 의 원본 값이 target-type 의 두 표현 가능한 값 사이에 있는 경우, 변환 결과는 구현체 정의에 따라 두 값 중 하나가 선택됩니다. [2]
  • 그 외의 경우, 동작은 정의되지 않습니다.
(C++23부터)
e) rvalue (C++11 이전) prvalue (C++11 이후) 타입 "pointer to cv1 Base "는 다음 조건들이 모두 충족될 경우 타입 "pointer to cv2 Derived "로 명시적으로 변환될 수 있습니다:
  • Derived 는 완전한 클래스 타입입니다.
  • Base Derived 의 기본 클래스입니다.
  • cv1 cv2 보다 더 큰 cv-qualification이 아닙니다.
만약 expression null pointer value 라면, 결과는 target-type 타입의 null pointer value입니다. 그렇지 않으면, 결과는 expression 이 가리키는 Base 타입 객체를 포함하는 Derived 타입 객체에 대한 포인터입니다.
다음 조건 중 하나라도 만족되면 프로그램은 ill-formed입니다:
  • Base Derived virtual base class 인 경우.
  • Base Derived 의 virtual base class의 base class인 경우.
  • "pointer to Derived "에서 "pointer to Base "로의 유효한 표준 변환이 존재하지 않는 경우.
만약 expression 이 null 포인터 값이 아니고 실제로 Derived 타입 객체의 base class 서브오브젝트를 가리키지 않는 경우, 동작은 정의되지 않습니다.
f) rvalue (C++11 이전) prvalue (C++11 이후) 타입 "cv1 T 타입의 Derived 멤버에 대한 포인터"는 다음 모든 조건이 충족될 때 타입 "cv2 T 타입의 Base 멤버에 대한 포인터"로 명시적으로 변환될 수 있습니다:
  • Derived 는 완전한 클래스 타입입니다.
  • Base Derived 의 기본 클래스입니다.
  • cv1 cv2 보다 더 큰 cv-한정자가 아닙니다.
만약 expression 이 null 멤버 포인터 값이면, 결과는 target-type 타입의 null 멤버 포인터 값입니다. 그렇지 않으면, 결과는 Base 클래스의 원본 (간접적일 수 있는) 멤버에 대한 포인터입니다.
"타입 T Base 멤버에 대한 포인터"에서 "타입 T Derived 멤버에 대한 포인터"로의 유효한 표준 변환이 존재하지 않으면 프로그램은 형식이 잘못되었습니다.
만약 expression 이 null 멤버 포인터 값이 아니고, 그것이 나타내는 멤버가 Base 클래스의 (직접적이거나 간접적인) 멤버가 아닌 경우, 동작은 정의되지 않습니다.
g) rvalue (C++11 이전) prvalue (C++11 이후) 타입 "pointer to cv1 void "는 cv1 cv2 보다 더 많은 cv-qualification이 아니고 T 가 객체 타입인 경우, 타입 "pointer to cv2 T "로 명시적으로 변환될 수 있습니다.
  • 만약 expression 이 null 포인터 값이면, 결과는 target-type 타입의 null 포인터 값입니다.
  • 만약 expression 이 메모리 내 바이트의 주소 A 를 나타내고 A T 의 정렬 요구사항을 만족하면, 결과 포인터 값도 A 를 나타냅니다.
  • 다른 모든 포인터 변환의 결과는 명시되지 않습니다.
  • 만약 expression 이 "pointer to cv3 T " 타입 객체의 이전 변환 결과라면, 결과는 원래 값을 가집니다.
(C++17 이전)
  • 만약 expression 이 메모리 내 바이트의 주소 A 를 나타내지만 A T 의 정렬 요구사항을 만족하지 않으면, 결과 포인터 값은 명시되지 않습니다.
  • 그렇지 않고 expression 이 객체 a 를 가리키고, a 와 포인터-상호변환 가능한(cv-qualification 무시) T 타입의 객체 b 가 존재하면, 결과는 b 를 가리키는 포인터입니다.
  • 그렇지 않으면, 포인터 값은 변환에 의해 변경되지 않습니다.
(C++17 이후)

모든 형변환 표현식과 마찬가지로, 결과는 다음과 같습니다:

  • target-type 이 lvalue 참조 타입인 경우 lvalue 또는 함수 타입에 대한 rvalue 참조인 경우 (C++11부터) ;
  • target-type 가 객체 타입에 대한 rvalue 참조인 경우 xvalue;
(since C++11)
  • 그렇지 않으면 prvalue입니다.
  1. 이 유형의 static_cast std::move 에서 이동 의미론을 구현하는 데 사용됩니다.
  2. IEEE 연산이 지원되는 경우, 반올림은 기본적으로 가장 가까운 값으로 설정됩니다.

포인터 상호 변환 가능 객체

두 객체 a b 가 다음 조건을 만족할 때 포인터 상호 변환 가능(pointer-interconvertible) 합니다:

  • 동일한 객체이거나,
  • 하나는 공용체 객체이고 다른 하나는 해당 객체의 비정적 데이터 멤버이거나,
  • 하나는 standard-layout 클래스 객체이고 다른 하나는 해당 객체의 첫 번째 비정적 데이터 멤버 또는 해당 객체의 기본 클래스 하위 객체이거나,
  • 객체 c 가 존재하여 a c 가 포인터 상호 변환 가능하고, c b 가 포인터 상호 변환 가능한 경우.
union U { int a; double b; } u;
void* x = &u;                        // x의 값은 "u를 가리키는 포인터"입니다
double* y = static_cast<double*>(x); // y의 값은 "u.b를 가리키는 포인터"입니다
char* z = static_cast<char*>(x);     // z의 값은 "u를 가리키는 포인터"입니다

참고 사항

기본-파생 변환( 다운캐스트 )을 static_cast 로 수행할 경우, 포인터/참조 대상 객체의 동적 타입 Derived 인지 확인하기 위한 런타임 검사를 수행하지 않습니다. 따라서 정적 다형성 구현과 같이 다른 방법으로 이 전제 조건이 보장된 경우에만 안전하게 사용할 수 있습니다. 안전한 다운캐스트는 dynamic_cast 를 사용하여 수행할 수 있습니다.

static_cast 는 특정 타입에 대한 함수-포인터 변환을 수행하여 함수 오버로드를 명확히 하는 데에도 사용될 수 있습니다. 예를 들어 다음과 같습니다:

std::for_each(files.begin(), files.end(),
              static_cast<std::ostream&(*)(std::ostream&)>(std::flush));

키워드

static_cast

예제

#include <iostream>
#include <vector>
struct B
{
    int m = 42;
    const char* hello() const
    {
        return "Hello world, this is B!\n";
    }
};
struct D : B
{
    const char* hello() const
    {
        return "Hello world, this is D!\n";
    }
};
enum class E { ONE = 1, TWO, THREE };
enum EU { ONE = 1, TWO, THREE };
int main()
{
    // 1. 정적 다운캐스트
    D d;
    B& br = d; // 암시적 변환을 통한 업캐스트
    std::cout << "1) " << br.hello();
    D& another_d = static_cast<D&>(br); // 다운캐스트
    std::cout << "1) " << another_d.hello();
    // 3. 좌측값에서 소멸값으로
    std::vector<int> v0{1, 2, 3};
    std::vector<int> v2 = static_cast<std::vector<int>&&>(v0);
    std::cout << "3) 이동 후, v0.size() = " << v0.size() << '\n';
    // 4. 폐기값 표현식
    static_cast<void>(v2.size());
    // 5. 초기화 변환
    int n = static_cast<int>(3.14);
    std::cout << "5) n = " << n << '\n';
    std::vector<int> v = static_cast<std::vector<int>>(10);
    std::cout << "5) v.size() = " << v.size() << '\n';
    // 6. 암시적 변환의 역변환
    void* nv = &n;
    int* ni = static_cast<int*>(nv);
    std::cout << "6) *ni = " << *ni << '\n';
    // 7a. 범위 있는 열거형을 int로
    E e = E::TWO;
    int two = static_cast<int>(e);
    std::cout << "7a) " << two << '\n';
    // 7b. int를 열거형으로, 열거형을 다른 열거형으로
    E e2 = static_cast<E>(two);
    [[maybe_unused]]
    EU eu = static_cast<EU>(e2);
    // 7f. 멤버 포인터 업캐스트
    int D::*pm = &D::m;
    std::cout << "7f) " << br.*static_cast<int B::*>(pm) << '\n';
    // 7g. void*를 임의 객체 포인터로
    void* voidp = &e;
    [[maybe_unused]]
    std::vector<int>* p = static_cast<std::vector<int>*>(voidp);
}

출력:

1) Hello world, this is B!
1) Hello world, this is D!
3) after move, v0.size() = 0
5) n = 3
5) v.size() = 10
6) *ni = 3
7a) 2
7f) 42

결함 보고서

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

DR 적용 대상 게시된 동작 올바른 동작
CWG 137 C++98 void 포인터의 const성과 volatile성을
제거할 수 있었음
이러한 경우 cv-한정자를
제거할 수 없음
CWG 427 C++98 다운캐스트가 직접 초기화와 모호할 수 있었음 이 경우 다운캐스트를 선택함
CWG 439 C++98 "객체 포인터"를 " void 포인터"로 변환한 후
다시 원래 포인터로 변환할 때, 결과 타입이 동일한
cv-한정자를 가져야만 값이 보존됨
cv-한정자가
달라도 됨
CWG 1094 C++98 부동소수점 값에서 열거형 값으로의
변환이 명시되지 않았음
명시됨
CWG 1320 C++11 범위 있는 열거형 값에서
bool로의 변환이 명시되지 않았음
명시됨
CWG 1412 C++98 " void 포인터"에서 "객체 포인터"로의
변환 결과가 불명확했음
명확해짐
CWG 1447 C++11 비트 필드에서 rvalue 참조로의 변환이
명시되지 않았음 (비트 필드에 참조를 바인딩할 수 없음)
명시됨
CWG 1766 C++98 정수 또는 열거형 값에서 열거형 값으로의 변환 시
expression 이 범위를 벗어나면 결과가 명시되지 않았음
이 경우 동작이
정의되지 않음
CWG 1832 C++98 정수 또는 열거형 값에서 열거형 값으로의
변환이 target-type 이 불완전할 수 있었음
허용되지 않음
CWG 2224 C++98 기본 클래스 타입의 멤버에서 파생 클래스 타입의
완전한 객체로의 변환이 유효했음
이 경우 동작이
정의되지 않음
CWG 2254 C++11 데이터 멤버가 없는 표준 레이아웃 클래스 객체가
첫 번째 기본 클래스와 포인터 상호 변환 가능했음
모든 기본 클래스와
포인터 상호 변환 가능함
CWG 2284 C++11 비표준 레이아웃 공용체 객체와 해당 객체의
비정적 데이터 멤버가 포인터 상호 변환 가능하지 않았음
포인터 상호 변환 가능함
CWG 2310 C++98 기본-파생 포인터 변환과
파생-기본 포인터-멤버 변환에서
파생 클래스 타입이 불완전할 수 있었음
완전해야 함
CWG 2338 C++11 고정된 기본 타입을 가진 열거형 타입으로의 변환 시
expression 이 범위를 벗어나면 정의되지 않은 동작이 발생함
먼저 기본 타입으로
변환함 (정의되지 않은 동작 없음)
CWG 2499 C++11 표준 레이아웃 클래스가 모든 기본 하위 객체가 동일한 주소를 가지더라도
포인터 상호 변환 불가능한 기본 클래스를 가질 수 있었음
가지지 않음
CWG 2718 C++98 기본-파생 참조 변환에서
파생 클래스 타입이 불완전할 수 있었음
완전해야 함
CWG 2882 C++98 static_cast < void > ( expr )
expr 에서 void 로의 암시적 변환 시퀀스를
형성하려는 시도를 하는지 불명확했음
이 경우 시도하지 않음

참조문헌

  • C++23 표준 (ISO/IEC 14882:2024):
  • 7.6.1.9 정적 변환 [expr.static.cast]
  • C++20 표준(ISO/IEC 14882:2020):
  • 7.6.1.8 Static cast [expr.static.cast]
  • C++17 표준 (ISO/IEC 14882:2017):
  • 8.2.9 Static cast [expr.static.cast]
  • C++14 표준(ISO/IEC 14882:2014):
  • 5.2.9 정적 변환 [expr.static.cast]
  • C++11 표준 (ISO/IEC 14882:2011):
  • 5.2.9 정적 변환 [expr.static.cast]
  • C++98 표준(ISO/IEC 14882:1998):
  • 5.2.9 Static cast [expr.static.cast]
  • C++03 표준(ISO/IEC 14882:2003):
  • 5.2.9 정적 변환 [expr.static.cast]

참고 항목