2016-07-28 4 views
1

私は、コンパイラがfooの準備をするためにどのくらいのメモリ知ることはできませんので、それはクラスが前方宣言なしで別のクラスのインスタンスへのポインタを持つことができないのはなぜですか?

class foo{ 
    foo bar; 
}; 

を行うことは不可能です知っています。 しかし、考えてみます。

class A{ 
    B::C* foo; 
}; 

class B{ 
    class C{ 
    }; 
}; 

コンパイラが、なぜこれが、その後は不可能であるCの定義に関係なく、正確にサイズを知っているだろうことは非常に合理的なようですか? (標準は、明示的にすることを禁じていますか?何のために?)、バックCに続いreinterpret_castそれをuintptr_tとしてfooを治療することである制約をバイパスする、私は非常に、粗な方法を持って


、これはただのです私は本当に(客観的)理由を得ていないことを示し、それはまともな理由なく使用された場合、それが本当に悪い習慣であることを私は知っています。


最後に、この規格では禁止されていることが判明しています。

class other {}; 

namespace N { 
    class foo { 
    other* p; 
    }; 

    class other {}; 
} 

を考慮すべきother*

+6

これはポインタなどに固有のものではありません。同じクラスのメンバーを除いて、一般に表示されるまで名前を使用することはできません。 – chris

+0

@chrisは、それがサイズの考慮に十分なポインタだと言っているだけではありませんか? – YiFei

+2

@YiFei 'other'は型名ではないかもしれませんし、変数の名前かもしれません。 – songyuanyao

答えて

1

一つの大きな課題は、以下のでしょうか?コンパイラの作業が多すぎます。 ::otherまたはN::otherで明示することはできますが、上記の場合でも混乱が生じます。

+0

Upvote!コンパイラのためのあまりにも多くの仕事に同意する(それは今ではあまりありませんか?):D;私の場合は関係していない標準で 'Name lookupが名前の明白な宣言を見つけなければならない'を見てください。私はそれが以前に宣言されたものを使用することを期待する、すなわち宣言されている場合は宣言されている。 – YiFei

+0

@YiFei、ありがとう。実際には、上記のサンプルコードはうまく動作しており、あいまいなエラーはありません。しかし、あなたの提案では、そのコードが壊れることがあります。さらに、あなたが求めている機能は、 'template'sを使ってすでに利用可能です。 – iammilind

+1

素晴らしいヒント!私は明示的にインスタンス化されたテンプレートをソースファイルに使用しています。 – YiFei

0

TL; DR:これは、標準で構文が記述されているためです。残念ながらそれはそれほど簡単です。例えばあなたのオープンスタンダード

  1. これは私が続くパスがありますc++11 draft

  2. セクション9のセクションについては、セクション9を参照してください。すぐに「9.2クラスのメンバー」というサブセクションがあります。構文全体が定義されています。読んだ後、member-declaratorに行く。我々の文脈において最も重要な部分はdeclaratorです。

  3. セクション8.宣言子。 p4で。 declaratorの構文があります。サポートされている派手な構文のすべての正式な定義を行った後、それはid-expressionに依存することがわかります。

  4. これは、5.1.1主要表現で定義されています。一般([expr.prim.general])。そしてそれはqualified-idunqualified-idでなければなりません。

あなたの質問は「なぜnamelookupはそれほど機能しないのですか」と言い換えることができます。しかし、それは別の質問です。

FWIW、それほど多くはないと思いますが、設計上の決定です。コンパイル単位のすべての失敗した解像度を追跡する必要があります。この文脈で怠惰なチェックを行うことは、かなり広範な意味合いを伴います。例えば後

+0

"宣言者はそこにはいません"とはどういう意味ですか? – YiFei

+0

'declarator'の定義です。私はおそらくそれを言い換えるべきです。 – luk32

0

class foo{ 
    other* bar; 
    ... 
}; 
class other{ 
    ... 
} 

&hellip。 (1)宣言されていない名前を使用し、(2)重要なセミコロンを欠い、あなたは

を尋ねるなぜこれがことが可能これではないでしょうか?

ホーリースタンダードでは、使用する前にすべての名前を宣言する必要があります。

与えられたC++の実装では、関数ポインタに関して言えば、データポインタでさえも異なるサイズ(void*はデータポインタを保持できることが保証されています)でもかまいません。

宣言先使用前の要件の代わりに暗黙のintのようにデフォルトを採用することができます。例えば。コンパイラはotherがクラス型であると仮定することができます。しかし、それは一般的にはあまり役に立ちませんし、言語を複雑にするでしょう。ただ、そう

class other; 

class foo{ 
    other* bar; 
    //... 
}; 

class other{ 
    //... 
}; 

class foo{ 
    class other* bar; 
    //... 
}; 

class other{ 
    //... 
}; 

は、別の方法としては、通常の前方宣言を使用することができます。

しかし、この特定のケースでは、その最初の使用でotherのに必要な最低限の宣言を組み合わせることが可能ですコンパイラはotherがクラス型であることを知っています。関数、または同義語charまたはvoid(基本の生データポインターのサイズに変動がある場合は、これらの型へのポインターが最も大きくなります)。


その後、主張:

を私は上記の投稿ダミーの例では、本当の意味を持っていないように思えるかもしれません。フォワード宣言なしでやりたい理由は、ネストされたクラスを取得したときにカプセル化を保持できる前方宣言がないことです。

これは間違っています。

など。これがうまく動作:

class Foo 
{ 
private: 
    class Other; 
    Other* bar; 

    class Other{}; 

public: 
    Foo(): bar(new Other) {} 
}; 

しかし、最初の使用、class Other* bar;での宣言とショートカットが、この場合には動作しません。これは、ネストされたクラスではなく、ネームスペースレベルのクラスとしてOtherを効果的に宣言するためです。

+0

争いはしませんが、「宣言(7項)は翻訳単位に1つ以上の名前を導入したり、以前の宣言によって導入された名前を再宣言したりする可能性があります。私たちが宣言の前に名前を使うことはできないとは言いません(私は間違っているのは分かっていますが、それ以上理由がわからない、あるいは前方宣言が必要ないということを知らないので)。ありがとう。 – YiFei

+0

@ YiFei:スコープのルールと名前の検索の結果としてそれを取得します。名前が宣言されていない場合、名前の参照は失敗します。標準では、名前検索が成功する必要があります。 –

+0

@YiFei私は答えにリンクされた11のドラフトを使用していますが、これは変わっていないと確信しています。 'id-qualifier'の定義は次のようになっています:"識別子は適切に宣言されていれば 'id-expression'です(7項)。*"そしておそらく実際に宣言されるまではありません。 – luk32

関連する問題