コンパイラはどのようにコードを作成できますか?この質問に答える
は、この質問に答えると同じようになります:どのようにコンパイラがそれをコンパイルすることができますか?
struct Type;
Type func(Type);
Live example
どのように存在し、まだその型を使用する関数を宣言しないタイプを定義することができますか?
答えは簡単です:コンパイルするコードはありません。実際には存在しない型を使用します。コンパイルするコードがないので、どのように失敗することができますか?
あなたのコードに何が関係しているのでしょうか?どのようにして、クラスがその親にテンプレートパラメータとして自分自身を送ることができるのでしょうか?
のは、あなたがそれをやっている時に、コンパイラの参照が何を分析してみましょう:
struct Foo : IFoo<Foo> { /* ... */ };
まず、コンパイルがこれを見ている:
struct Foo ...
コンパイラは今Foo
が存在することを知っている、まだそれが不完全ですタイプ。それはIFoo
が何であるかを知っている、そしてそれはFoo
がタイプであることを知っている
... : IFoo<Foo> ...
:
は今、彼はそれを見ています。コンパイラは今はそのタイプでIFoo
をインスタンス化する必要があります。
template <class T> struct IFoo
{
virtual T addX(T foo, double val) = 0;
};
だから、本当に、それはそれで、関数の宣言で、クラスを宣言します。あなたは、不完全な型の関数が宣言されていることを確認しました。ここでも同じことが起こります。その時点で、このコードは次のようにあなたのコードが可能です:
struct Foo;
template struct IFoo<Foo>; // instanciate IFoo with Foo
本当にそこには魔法はありません。
ここで、もっと説得力のある例を考えてみましょう。そのことについて何?
template<typename T>
struct IFoo {
void stuff(T f) {
f.something();
}
};
struct Foo : IFoo<Foo> {
void something() {}
};
どのようにすることができ、不完全な形でのコンパイラの呼び出しsomething
?
事はありません。 something
を使用するとFoo
が完了します。これは、テンプレート関数が使用されたときにのみインスタンス化されるためです。
テンプレートでも関数定義を分けることができますか?
template<typename T>
struct IFoo {
void stuff(T f);
};
template<typename T>
void IFoo<T>::stuff(T f) {
f.something();
}
struct Foo : IFoo<Foo> {
void something() {}
};
素晴らしい!純粋な仮想関数であなたの例とまったく同じように見えるでしょうか?別の有効な変換を行いましょう:
template<typename T>
struct IFoo {
void stuff(T f);
};
struct Foo : IFoo<Foo> {
void something() {}
};
// Later...
template<typename T>
void IFoo<T>::stuff(T f) {
f.something();
}
完了! Foo
が完了した後、関数を後で定義しました。そして、これは何が起こるのかです:コンパイラは使用されるときにのみIFoo<Foo>::stuff
をinstanciateします。そしてそれが使用されるポイントは、Foo
です。そこにも魔法はありません。
は、なぜあなたは、その後IFoo
内部T
メンバ変数を宣言することはできませんか?
シンプル、同じ理由で、このコードはコンパイルされません理由:それは不完全な型の変数を宣言する意味がありません
struct Bar;
Bar myBar;
。
'memberVar'は' Foo'(間接的に)自身の別のインスタンスを保持します。本質的にそれは 'sizeof(Foo)== 2 * sizeof(Foo)'を作るでしょう。もちろん、動作しません。:-) –
すてきな答えをありがとう。今私には明らかです。 – jaba