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);
있습니다.