1. ホーム
  2. c++

[解決済み] 3つの主要なC++コンパイラで、プログラムのコンパイルが異なっています。どれが正しいのでしょうか?

2022-05-15 14:28:09

質問

前回の質問に対する興味深いフォローアップとして(実用上の重要性は高くないが)。 なぜ 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

だから、義務的な質問は、どれが正しいかです :)

(私はclang版に強く惹かれましたし、typedefで型変更した後に変数宣言をやめるというmsvcのやり方はちょっと変な気がします)

どのように解決するのですか?

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 が関数型のキャスト式と誤認して、一時的に Cy という変数の宣言であると誤認してしまいます。 y という変数の宣言と誤解します。 C .