이제 변환 생성자는 '중괄호로 묶여진 값들도 생성자의 인자로 받아들인다'.
#include <iostream>
class A {
public:
A(int) {}
A(int, int) {}
A(int, int, int) {}
};
int main(void)
{
A a {0, 0}; // calls A::A(int, int);
A b{0, 0}; // calls A::A(int, int);
A c = {0, 0}; // calls A::A(int, int);
A d {0, 0, 0}; // calls A::A(int, int, int);
}
하지만 여기에는 특별한 규칙이 있는데 '축소 변환(narrowing)' 같은 상황을 방지한다.
A e(1.1); // calls A::A(int);
A f {1.1}; // error
그리고 다음과 같은 상황이 가능하다.
A g(); // A를 리턴하는 함수 g 선언
A h{}; // 기본 생성자 호출
`A g()`를 사용했을때 우리가 기대했던 것은 `A`의 기본 생성자를 호출하는 것이였을 테지만, 컴파일러 입장에서 보면 `A`를 리턴하는 함수 `g`의 선언으로밖에 보이지 않는다.
하지만 `A h{}`를 사용하게 되면 컴파일러 입장에서 `A`의 기본 생성자를 호출하려는 의도를 파악할 수 있다.
그리고 만약 생성자가 `std::initializer_list`를 인수로 받아들인다면 어떤 상황에서든 `{}` 초기화는 해당 생성자를 호출할 것이다.
이는 벡터와 같이 인수를 무한으로 받아들이고자 할 때 유용하게 사용된다.
struct A {
A(int) {}
A(int, int) {}
A(int, int, int) {}
A(std::initializer_list<int>) {}
};
A a {0, 0}; // calls A::A(std::initializer_list<int>)
A b(0, 0); // calls A::A(int, int)
A c = {0, 0}; // calls A::A(std::initializer_list<int>)
A d {0, 0, 0}; // calls A::A(std::initializer_list<int>)
[C++11] Range-based for loops (0) | 2023.08.24 |
---|---|
[C++11] Special member functions for move semantics (1) | 2023.08.24 |
[C++11] explicit conversion functions (0) | 2023.08.24 |
[C++11] Inline namespaces (0) | 2023.08.24 |
[C++11] Non-static data member initializers (0) | 2023.08.24 |