2014-02-19 2 views
1

다음 코드에서 이동 생성자 호출이 생략 된 이유는 무엇입니까?생성자 템플릿 엘레멘트 이동

struct Foo { 
    Foo() = default; 

    Foo(const Foo&) { cout << "Foo(const Foo&)" << endl; } 
    template<class T> Foo(T&&) { cout << "Foo<T>(T&&)" << endl; } 
}; 

auto f = Foo{}; 

출력 : Foo<T>(T&&)

, 그 소리 3.3에 검사 g ++ 4.9.

기본값 또는 사용자 정의 이동 생성자 결과를 출력하지 않고 추가합니다. 왜 생성자 템플릿을 호출하는 호출이 컴파일러에 의해 생략되지 않는가? 그리고 템플릿이 아닌 템플릿에 대한 호출이 사용자 정의 (즉, 컴파일러에서 부작용이없고 안전하게 생략 할 수 있음을 알 수있는 방법)해도 제거되지 않는 이유는 무엇입니까?

+0

다른 최적화 수준을 사용해 보셨습니까? –

+0

아니요, 기본 플래그를 사용했지만 최적화 수준이 아니라 언어 표준의 문제인 것으로 보입니다 (최적화가 올바른 형식의 프로그램 동작을 변경하지 않아야 함). – Hertz

답변

3

이동 생성자이고 따라서 elision 후보가 될 수 있으려면 생성자가 템플릿 인스턴스가 아니어야합니다 (마찬가지로 템플릿이 동일한 서명으로 생성자를 생성 할 수 있으므로 기본 버전이 생성되지 않습니다).

예에서 명시 적 복사 생성자가 있으면 기본 이동 생성자가 암시 적으로 생성되지 않으므로 생성자 템플릿이 인스턴스화됩니다 (서명을 공유하더라도 이동 생성자가 아닙니다).

명시 적 (기본 또는 비활성) 이동 생성자를 추가하면이 생성자가 사용됩니다 (생략 할 수는 있지만 반드시 생략 할 수는 없습니다).

+0

따라서 생성자 템플릿에 대해 복사/이동 제거가 수행되지 않는다고 명시해야합니다. 하지만 명시 적으로 defaulted move 생성자가 출력에 추가 된 이유는 무엇입니까? – Hertz

+0

이제 그 이유를 알 수 있습니다. 사용자 정의 복사 생성자는 컴파일러가 생성자를 생성하지 못하도록합니다. – Hertz

+0

이 클레임 템플릿에서 elision을 방지하기위한 표준에 대한 참조를 제공 할 수 있습니까? –

0

이유는 복사 및 이동 생성자가 비 템플릿 (12.8/2, 12.8/3)으로 정의되고 복사/이동 엘레멘트 규칙이이 생성자 템플릿 (12.8/31)에 적용되지 않기 때문입니다.

사용자 정의 된 복사 생성자가 컴파일러가 기본적으로 암시 적으로 기본 생성자를 생성하지 못하게하므로 기본 생성자 또는 사용자 정의 이동 생성자 (이 경우)의 추가 결과가 다른 결과를 가져오고 (결과적으로 elision을 이동합니다.) 따라서 처음부터 대답이 잘못되었습니다. :

12.8/7 클래스 정의가 명시 적으로 복사 생성자를 선언하지 않으면 그 중 하나가 암시 적으로 선언됩니다. 클래스 정의가 이동 생성자 또는 이동 대입 연산자를 선언하면 암시 적으로 선언 된 복사 생성자는 삭제됨으로 정의됩니다. 그렇지 않으면 기본값으로 정의됩니다 (8.4).

+0

이 클레임에 대한 표준에 대한 참조를 제공 할 수 있습니까? –

+0

이 질문 자체가 왜 추가되지 않았는지 확실하지 않습니다. –