3 개의 주요 C ++ 컴파일러에서 다르게 컴파일되는 프로그램. 어느 것이 맞습니까? 이전 질문에

이전 질문에 대한 흥미로운 후속 조치 (실제적으로 크게 중요하지는 않음) :
왜 C ++에서 변수를 선언 할 때 변수 이름을 괄호로 묶을 수 있습니까?

괄호 안의 선언과 삽입 된 클래스 이름 기능 을 결합하면 컴파일러 동작과 관련하여 놀라운 결과를 얻을 수 있다는 것을 알았습니다 .

다음 프로그램을 살펴보십시오.

#include <iostream>
struct B
{
};

struct C
{
  C (){ std::cout << "C" << '\n'; }
  C (B *) { std::cout << "C (B *)" << '\n';}
};

B *y = nullptr;
int main()
{
  C::C (y);
}
  1. g ++ 4.9.2로 컴파일하면 다음과 같은 컴파일 오류가 발생합니다.

    main.cpp:16:10: error: cannot call constructor 'C::C' directly [-fpermissive]
  2. MSVC2013 / 2015로 성공적으로 컴파일되고 인쇄됩니다. C (B *)

  3. clang 3.5로 성공적으로 컴파일되고 인쇄됩니다. C

그래서 어떤 질문이 옳은가? 🙂

(기술적으로 typedef로 유형을 변경 한 후 변수 선언을 중지하는 msvc 방법은 clang 버전으로 강력하게 흔들 렸습니다.)



답변

GCC는 적어도 C ++ 11 조회 규칙에 따르면 정확합니다. 3.4.3.1 [class.qual] / 2는 중첩 된 이름 지정자가 클래스 이름과 동일한 경우 삽입 된 클래스 이름이 아닌 생성자를 참조하도록 지정합니다. 예제를 제공합니다.

B::A ba;           // object of type A
A::A a;            // error, A::A is not a type name
struct A::A a2;    // object of type A

MSVC 가 생성자 매개 변수로 임시 C를 만드는 함수 스타일 캐스트 표현식으로 잘못 해석 한 것처럼 보입니다 y. Clang은이 y를 type 이라는 변수의 선언으로 잘못 해석합니다 C.


답변

G ++는 오류를 제공하므로 정확합니다. 생성자는 new연산자 없이 이러한 형식으로 직접 호출 할 수 없기 때문 입니다. 코드가를 호출하더라도 C::C생성자 호출처럼 보입니다. 그러나 C ++ 11 표준 3.4.3.1에 따르면 이것은 합법적 인 함수 호출이나 유형 이름이 아닙니다 ( Mike Seymour의 답변 참조 ).

Clang은 올바른 함수를 호출하지 않기 때문에 잘못되었습니다.

MSVC는 합리적이지만 여전히 표준을 따르지 않습니다.