web-dev-qa-db-ja.com

空の角かっこを持つデフォルトのコンストラクター

空の丸括弧(括弧)のセットがC++のデフォルトコンストラクターを呼び出すのに有効でない理由はありますか?

MyObject  object;  // ok - default ctor
MyObject  object(blah); // ok

MyObject  object();  // error

私は毎回自動的に「()」と入力するようです。これが許可されない正当な理由はありますか?

189
Martin Beckett

最も厄介な解析

これは、「C++の最も厄介な解析」と呼ばれるものに関連しています。基本的に、コンパイラーが関数宣言として解釈できるものはすべて、関数宣言として解釈されます。

同じ問題の別のインスタンス:

std::ifstream ifs("file.txt");
std::vector<T> v(std::istream_iterator<T>(ifs), std::istream_iterator<T>());

vは、2つのパラメーターを持つ関数の宣言として解釈されます。

回避策は、括弧の別のペアを追加することです:

std::vector<T> v((std::istream_iterator<T>(ifs)), std::istream_iterator<T>());

または、C++ 11およびリスト初期化(均一な初期化とも呼ばれる)を使用できる場合:

std::vector<T> v{std::istream_iterator<T>{ifs}, std::istream_iterator<T>{}};

これでは、関数宣言として解釈する方法はありません。

155
Constantin

関数の宣言として扱われるためです:

int MyFunction(); // clearly a function
MyObject object(); // also a function declaration
100

関数の宣言にも同じ構文が使用されます-例:関数object、パラメーターを取らず、MyObjectを返す

50

コンパイラは、それが引数をとらず、MyObjectインスタンスを返す関数の宣言だと考えているためです。

11
Fred Larson

より詳細な構築方法を使用することもできます。

MyObject object1 = MyObject();
MyObject object2 = MyObject(object1);

C++ 0xでは、これによりautoも許可されます。

auto object1 = MyObject();
auto object2 = MyObject(object1);
8
dalle

コンパイラーは、このステートメントが次のことを認識していないと思います。

MyObject object();

は、コンストラクター呼び出しまたはobjectという名前で戻り型MyObjectでパラメーターなしの関数を宣言する関数プロトタイプです。

7
Black

何度も述べたように、それは宣言です。後方互換性のためにそうなっています。 C++の多くの分野の1つで、そのレガシーのために間抜け/一貫性のない/痛みを伴う/偽物です。

5
Michael Burr

N4296 [dcl.init]から:

[ 注意:
_()_はinitializerの構文では許可されていないため、X a();はクラスXのobjectが、functionの宣言は引数(X)を返します。フォーム()は、他の特定の初期化コンテキスト(5.3.4、5.2.3、12.6.2)で許可されています。
—メモの終了]

4
Andreas DM

他の人が言ったように、それは関数宣言です。 C++ 11以降では、デフォルトのコンストラクタが使用されていることを明示的に示す空のsomethingを確認する必要がある場合は、ブレースの初期化を使用できます。

Jedi luke{}; //default constructor
1
Hitokage