6

다음과 같은 프로그램을 고려 컴파일에 실패 : GCC 4.7.2, GCC 4.8.0, 그리고 연타 3.2로 컴파일 할 때간단한 프로그램

struct X 
{ 
    X(int, int) { } 
    X(X&&) { } 
}; 

int main() 
{ 
    X x({0, 1}); // Doesn't compile on ICC 13.0.1, compiles on 
        // Clang 3.2, GCC 4.7.2, and GCC 4.8.0 beta. 
} 

을,이 프로그램은 (다음을 수행 *)

  1. 구축해에게 형의 임시 X를 통과 후, 생성자 01 값;
  2. X을 임시로 이동 구성합니다.

대신 ICC 13.0.1에서는 컴파일되지 않습니다.

질문 1 : 누가 옳았습니까?

(*) 는 사실, 이동 생성자에 임시의 생성과 호출이 생략하지만, -fno-elide-constructors 옵션을 사용하여 컴파일하고 생성자에 약간의 출력물을 추가 이것이 무슨 일인지는 것을 알 수있다.


지금 균일 초기화가 사용되는 위의 프로그램, 다음, 약간의 변화를 고려 x 직접를 초기화 :

int main() 
{ 
    X x{ {0, 1} }; // ERROR! Doesn't compile. 
//  ^........^ 
} 

나는 중괄호의 사용을 기대하는 대신하지 않을 괄호를 사용하여 여기에 무엇이든 바꿀 수는 있지만 어쨌든이 프로그램은 에서 컴파일하지 않았다. (Clang 3.2, GCC 4.7.2, GCC 4.8.0 베타 및 ICC 13.0.1에서 테스트 한 컴파일러 중).

질문 2 : 왜?

+0

두 번째 오류는 어떤 오류인지 궁금합니다. –

+0

@ NicolBolas : [여기] (http://liveworkspace.org/code/10CpDi$73)에서 확인해보십시오. 컴파일러를 선택할 수 있습니다. –

+0

당신은 이곳이 얼마나 효과가 있는지 알기에 충분히 오랫동안 여기에 왔습니다. 그것이 적절하다면, 질문에 넣으십시오. 일부 실제 작업 영역 페이지로 링크하지 마십시오. –

답변

2

이것은 모든 컴파일러의 버그입니다. §8.5.4/3 다음과 같이 개체 또는 T 타입의 참조

목록 초기화가 정의 말한다 :

- 이니셜 라이저 목록에 요소가없고 T는와 클래스 타입 인 경우 기본 생성자이면 개체는 값으로 초기화됩니다.

- 그렇지 않으면 T가 집계 일 경우 집계 초기화가 수행됩니다 (8.5.1).

- T는 표준 : initializer_list 특수화 경우에 대하여 설명하고, 객체를 초기화로 그렇지 initializer_list 객체 ...

구성되어있다 - 그렇지 않으면, T 클래스 타입 인 경우, 생성자는 깊이 생각한. 적용 가능한 생성자가 열거되고 가장 적합한 것이 과부하 해결 (13.3, 13.3.1.7)을 통해 선택됩니다. 인수를 변환하기 위해 축소 변환 (아래 참조)이 필요한 경우 프로그램이 잘못 작성됩니다.

- 그렇지 않으면 T가 참조 유형 인 경우 T가 참조하는 임시의 prvalue가 목록에서 초기화되고 참조가 해당 임시에 바인딩됩니다.

- 이니셜 라이저 목록에 단일 요소가 있으면 개체 또는 참조가 해당 요소에서 초기화됩니다. 요소를 T로 변환하기 위해 축소 변환 (아래 참조)이 필요한 경우 프로그램이 잘못 작성됩니다.

...

꽤 몇 가지 경우가 있습니다. rvalue 참조에 바인딩 된 prvalue 임시 객체를 실제로 목록으로 초기화하는 것입니다.

GCC의 경우, 단일 요소 초기화 목록에 대해 위에서 언급 한 마지막 항목을 적용하려고합니다. 생성자 시그니처를 X(X&&, int = 3)으로 변경하면 { {0, 1} } 이니셜 라이저가 실패하지만 { {0, 1}, 3 }이 성공합니다. 요소가 braced-init-list이기 때문에 단일 항목이 성공해야합니다. 그 경우에는 괄호와 유사하게 여분의 중괄호를 사용할 수 있다고 생각합니다. 그러나이 실패는 중괄호 제거로 인한 GCC의 다른 단점과 유사합니다.

제 생각에는 컴파일러가 목록을 형식이 아닌 개체로 취급하려고 할 때 문제가 발생한다는 것입니다. 다시 괄호로 묶인 인수 목록으로 변환하기는 어렵습니다.

, 오류 메시지합니다 (LWS 링크에 대한 감사)에서 더 구체적으로

  • 을 찾고 ICC는 식을 기대 주장한다. 기본 문법에 따르면 braced-init-lists는 표현식뿐만 아니라 다른 braced-init-lists도 포함 할 수 있으므로 잘못되었습니다. : " 'X'로 초기화리스트 인수를 변환 할 수 없습니다 후보 생성자 실행 가능하지"하지만 변환이 X x{ X{0, 0 } };를 사용하여 명시 적이면 그것은 작동

  • 연타는 말한다. 그건 말이되지 않습니다. 목록에는 변환 할 유형이 없으므로 전환이 아닙니다. 목록 초기화입니다.

  • GCC는 "X & & ''에서 ''에서 인수 1 알려진 전환"을 말한다도 기준에 바인딩 임시을 정의하는 지점에 도착하지 않았다 그것을 제안. Clang과 마찬가지로 가짜 전환을 시도하는 것으로 보이며 X{0,0}을 지정하면 해결됩니다.

+0

여기서 두 번째 예제에만 초점을 맞추고 있습니다. –

+0

@AndyProwl 예. 나는 ICC가 없으며 첫 번째 예가 정확하다고 생각한다. (사실 두 번째 프로그램 역시 마찬가지라고 생각합니다.) – Potatoswatter

+0

두 프로그램 모두 컴파일해야한다고 생각하십니까? (btw, [여기] (http://liveworkspace.org/code/10CpDi$87)에서 ICC를 선택할 수 있습니다. –