何が起こるかを明確にするためだけに。この例を見てください
int main() {
float a = 0;
{
int(a); // no-op?
a = 1;
}
cout << a;
}
何を出力しますか?まあ、それは出力されます0
。上記のint(a)
は、次の 2 つの異なる方法で解析できます。
- int にキャストして結果を破棄する
- という変数を宣言します
a
。ただし、識別子を囲む括弧は無視してください。
関数スタイルのキャストがステートメントで使用され、宣言のようにも見えるような状況が発生した場合、コンパイラは常にそれを宣言として受け取ります。構文的に宣言できない場合 (コンパイラーはそれを判断するために行全体を調べます)、それは式であると見なされます。したがって、上の内側に代入しa
、外側a
をゼロのままにします。
今、あなたのケースはまさにそれです。A
と呼ばれるクラス内で呼び出される識別子を(誤って)宣言しようとしていますX
:
X (X::A); // parsed as X X::A;
コンパイラーは、宣言されていないデフォルトコンストラクターについてうめき声を上げます。これは、静的であることを前提として、デフォルトで構築されているためです。しかし、X のデフォルト コンストラクターがあったとしてA
も、X の静的メンバーでもなく、ブロック スコープで X の静的を定義/宣言することもできないため、もちろん間違っています。
いくつかのことを行うことで、宣言のように見えないようにすることができます。まず、式全体を括弧で囲むことができます。これにより、宣言のように見えなくなります。または、キャスト先の型を括弧で囲みます。これらの明確化は両方とも、他の回答で言及されています。
(X(X::A)); (X)(X::A)
オブジェクトを実際に宣言しようとすると、似ていますが明確なあいまいさが生じます。この例を見てください:
int main() {
float a = 0;
int b(int(a)); // object or function?
}
int(a)
呼び出されるパラメーターの宣言と、float 変数の int への明示的な変換 (キャスト) の両方が可能なためa
、コンパイラーはそれが宣言であると再度判断します。b
したがって、整数の引数を取り、整数を返す という関数をたまたま宣言します。上記の曖昧さ回避に基づいて、それを明確にする方法がいくつかあります。
int b((int(a))); int b((int)a);