C ++ 17 업데이트
C ++ 17에서는 A_factory_func()임시 객체 생성 (C ++ <= 14)에서 C ++ 17에서이 표현식이 초기화 된 (느슨하게 말하면) 객체의 초기화를 지정하는 것으로 변경되었습니다. 이러한 객체 ( "결과 객체"라고 함)는 선언 (예 a1:), 초기화가 종료 될 때 생성 된 인공 객체 또는 참조 바인딩에 객체가 필요한 A_factory_func();경우 (예 : 개체가 A_factory_func()존재해야하는 변수 나 참조가 없기 때문에 "임시 구체화"라는 개체가 인위적으로 생성 됩니다.
우리의 경우 예로서,의 경우 a1와 a2특별한 규칙 같은 선언에서, 같은 유형의 초기화 prvalue의 결과 개체 말할 a1변수 a1때문에, 그리고 A_factory_func()직접적으로 개체를 초기화합니다 a1. A_factory_func(another-prvalue)외부 prvalue의 결과 객체를 내부 prvalue의 결과 객체로 "통과" 하기 만하면 중개 기능 스타일 캐스트는 아무런 영향을 미치지 않습니다 .
A a1 = A_factory_func();
A a2(A_factory_func());
A_factory_func()반환 되는 유형에 따라 다릅니다. A복사 생성자가 명시 적 인 경우 첫 번째 생성자가 실패한다는 점을 제외하고 는 -를 반환한다고 가정합니다 . 8.6 / 14 읽기
double b1 = 0.5;
double b2(0.5);
이것은 내장 타입이기 때문에 똑같이하고 있습니다 (여기서는 클래스 유형이 아닙니다). 8.6 / 14를 읽으십시오 .
A c1;
A c2 = A();
A c3(A());
이것은 똑같이하지 않습니다. 첫 번째 A는 비 POD 인 경우 기본적으로 초기화되며 POD에 대한 초기화를 수행하지 않습니다 ( 8.6 / 9 읽기 ). 두 번째 사본은 다음을 초기화합니다. 값을 임시로 초기화 한 다음 해당 값을 c2( 5.2.3 / 2 및 8.6 / 14 읽기)에 복사합니다 . 물론 명시 적이 아닌 복사 생성자가 필요합니다 ( 8.6 / 14 및 12.3.1 / 3 및 13.3.1.3/1 읽기 ). 세 번째는 a c3를 반환하고 a 를 반환하는 A함수에 대한 함수 포인터를받는 함수에 대한 함수 선언을 만듭니다 A( 8.2 읽기 ).
초기화 직접 및 복사 초기화
그것들은 동일하게 보이고 동일하게 수행되어야하지만,이 두 형태는 경우에 따라 현저히 다릅니다. 초기화의 두 가지 형태는 직접 및 복사 초기화입니다.
T t(x);
T t = x;
우리는 그들 각각에 귀속되는 행동이 있습니다 :
- 직접 초기화는 오버로드 된 함수에 대한 함수 호출처럼 작동합니다.이 경우 함수는 (함수
T포함 explicit) 의 생성자이며 인수는 다음과 같습니다.x 입니다. 과부하 해결은 가장 일치하는 생성자를 찾고 필요할 때 암시 적 변환이 필요합니다.
- 복사 초기화는 암시 적 변환 시퀀스를 구성합니다 .
x유형의 객체 로 변환 을 시도 합니다 T. 그런 다음 해당 객체를 초기화 된 객체로 복사 할 수 있으므로 복사 생성자도 필요하지만 아래에서는 중요하지 않습니다.
보시다시피, 복사 초기화 는 어떤 식 으로든 가능한 암시 적 변환과 관련하여 직접 초기화의 일부입니다. 직접 초기화에는 모든 생성자가 호출 가능 하며 추가로 가 인수 형식을 일치 할 필요가있는 암시 적 변환을 수행 할 수 있습니다, 초기화를 복사 하나의 암시 적 변환 시퀀스를 설정할 수 있습니다.
나는 열심히 노력 하여 생성자를 통해 "명백한"을 사용하지 않고 각 양식에 대해 다른 텍스트를 출력하는 다음 코드를 얻었습니다explicit .
#include <iostream>
struct B;
struct A {
operator B();
};
struct B {
B() { }
B(A const&) { std::cout << "<direct> "; }
};
A::operator B() { std::cout << "<copy> "; return B(); }
int main() {
A a;
B b1(a); // 1)
B b2 = a; // 2)
}
// output: <direct> <copy>
어떻게 작동하고 왜 결과를 출력합니까?
직접 초기화
먼저 전환에 대해 아무것도 모릅니다. 생성자를 호출하려고 시도합니다. 이 경우 다음 생성자를 사용할 수 있으며 정확히 일치합니다 .
B(A const&)
해당 생성자를 호출하는 데 필요한 변환은 사용자 정의 변환보다 훨씬 적습니다 (여기서 const 한정 변환도 수행되지 않음). 따라서 직접 초기화가 호출됩니다.
복사 초기화
위에서 언급했듯이, 복사 초기화는 a유형이 B없거나 파생 되지 않은 경우 변환 시퀀스를 구성 합니다 (여기서는 분명히 그렇습니다). 변환을 수행하는 방법을 찾고 다음 후보를 찾습니다.
B(A const&)
operator B(A&);
변환 함수를 어떻게 다시 작성했는지 주목하십시오. 매개 변수 유형은 this포인터가 아닌 유형을 나타내는 포인터 유형을 반영합니다 . 이제 우리는이 후보들을 x논쟁으로 부릅니다 . 승자가 변환 함수입니다. 두 개의 후보 함수가 모두 동일한 유형에 대한 참조를 허용하는 경우 더 적은 const 버전 (비 const 멤버 함수를 선호하는 메커니즘은 -const 객체).
변환 함수를 const 멤버 함수로 변경하면 변환이 모호합니다 (둘 다 매개 변수 유형이 되었기 때문에 A const&). -pedantic그래도 전환 하면 적절한 모호성 경고가 출력됩니다.
이 두 가지 형식이 어떻게 다른지 더 명확하게 만드는 데 도움이되기를 바랍니다.
A c1; A c2 = c1; A c3(c1);있습니다.