Direct-initialization
명시적인 생성자 인수 집합으로 객체를 초기화합니다.
목차 |
구문
T
객체
(
인수
);
T
객체
|
(1) | ||||||||
T
객체
{
인수
};
|
(2) | (C++11부터) | |||||||
T
(
다른_객체
)
T
|
(3) | ||||||||
static_cast<
T
>(
다른_객체
)
|
(4) | ||||||||
new
T
(
인수들, ...
)
|
(5) | ||||||||
클래스
::
클래스
()
:
멤버
(
인수들, ...
)
{
...
}
|
(6) | ||||||||
[
인수
]() {
...
}
|
(7) | (C++11부터) | |||||||
설명
직접 초기화(direct-initialization)는 다음과 같은 상황에서 수행됩니다:
직접 초기화(direct-initialization)의 효과는 다음과 같습니다:
-
만약
T가 배열 타입인 경우,
|
(C++20 이전) |
struct A { explicit A(int i = 0) {} }; A a[2](A(1)); // OK: initializes a[0] with A(1) and a[1] with A() A b[2]{A(1)}; // error: implicit copy-list-initialization of b[1] // from {} selected explicit constructor |
(C++20 이후) |
-
만약
T가 클래스 타입이라면,
|
(C++17부터) |
-
-
T의 생성자들을 검토하고 오버로드 해결을 통해 가장 적합한 항목을 선택합니다. 그런 다음 생성자를 호출하여 객체를 초기화합니다.
-
struct B { int a; int&& r; }; int f(); int n = 10; B b1{1, f()}; // OK, lifetime is extended B b2(1, f()); // well-formed, but dangling reference B b3{1.0, 1}; // error: narrowing conversion B b4(1.0, 1); // well-formed, but dangling reference B b5(1.0, std::move(n)); // OK |
(since C++20) |
-
그렇지 않고
T가 비클래스 타입이지만 소스 타입이 클래스 타입인 경우, 소스 타입과 해당 기본 클래스들의 변환 함수들을 검사하고 오버로드 해결을 통해 가장 적합한 매치를 선택합니다. 선택된 사용자 정의 변환은 초기화 표현식을 초기화되는 객체로 변환하는 데 사용됩니다. -
그렇지 않고
T가 bool 이고 소스 타입이 std::nullptr_t 인 경우, 초기화된 객체의 값은 false 입니다. -
그렇지 않은 경우, 필요한 경우
표준 변환
을 사용하여
other
의 값을
T의 cv-unqualified 버전으로 변환하며, 초기화되는 객체의 초기값은 (변환될 수 있는) 해당 값입니다.
참고 사항
직접 초기화(direct-initialization)는 복사 초기화(copy-initialization)보다 더 허용적입니다: 복사 초기화는 비- explicit 생성자와 비-explicit 사용자 정의 conversion functions 만 고려하는 반면, 직접 초기화는 모든 생성자와 모든 사용자 정의 변환 함수를 고려합니다.
직접 초기화 구문 (1) (둥근 괄호 사용)을 이용한 변수 선언과 함수 선언 사이에 모호성이 발생하는 경우, 컴파일러는 항상 함수 선언을 선택합니다. 이러한 모호성 해소 규칙은 때로 직관적이지 않으며 가장 성가신 구문 분석(most vexing parse) 로 불립니다.
#include <fstream> #include <iterator> #include <string> int main() { std::ifstream file("data.txt"); // 다음은 함수 선언입니다: std::string foo1(std::istreambuf_iterator<char>(file), std::istreambuf_iterator<char>()); // 이는 foo1이라는 함수를 선언하며, 반환 타입은 std::string, // 첫 번째 매개변수는 std::istreambuf_iterator<char> 타입이고 이름이 "file"이며, // 두 번째 매개변수는 이름이 없고 std::istreambuf_iterator<char>() 타입으로, // 함수 포인터 타입 std::istreambuf_iterator<char>(*)()로 재작성됩니다 // C++11 이전 해결책 (변수 선언) - 인수 중 하나에 추가 괄호 사용: std::string str1((std::istreambuf_iterator<char>(file)), std::istreambuf_iterator<char>()); // C++11 이후 해결책 (변수 선언) - 인수 중 하나에 목록 초기화 사용: std::string str2(std::istreambuf_iterator<char>{file}, {}); }
예제
#include <iostream> #include <memory> #include <string> struct Foo { int mem; explicit Foo(int n) : mem(n) {} }; int main() { std::string s1("test"); // const char*로부터 생성자 std::string s2(10, 'a'); std::unique_ptr<int> p(new int(1)); // OK: explicit 생성자 허용됨 // std::unique_ptr<int> p = new int(1); // 오류: 생성자가 explicit임 Foo f(2); // f는 직접 초기화됨: // 생성자 매개변수 n은 rvalue 2로부터 복사 초기화됨 // f.mem은 매개변수 n으로부터 직접 초기화됨 // Foo f2 = 2; // 오류: 생성자가 explicit임 std::cout << s1 << ' ' << s2 << ' ' << *p << ' ' << f.mem << '\n'; }
출력:
test aaaaaaaaaa 1 2