template <typename T>
class Node
{...};
int main
{
Node* ptr;
ptr = new Node<int>;
}
コンパイルに失敗します私はポインタを次のように宣言する必要があります
Node<int>* ptr;
まだクラスを作成していないポインターを宣言するときに型を指定する必要があるのはなぜですか、コンパイラーはそれが指す型を知る必要があるのはなぜですか。そして、汎用ポインタを作成して、後で割り当てるタイプを決定することはできません。
テンプレート化は、コンパイル時に型を解決します。新しいNode<int>
オブジェクトを割り当てる場合、ポインターはコンパイル時にそれが正確にどの型であるかを知っている必要があります。
Node<int>
とNode<std::vector>
は、バイナリ(テンプレートパラメーターに応じてオブジェクトのバイナリレイアウトが完全に変化する)で大きく異なる可能性があるため、テンプレートへの未解決のポインター型を指定しても意味がありません。
まず、ノードの共通の親クラスを定義する必要があります。
class NodeBase
{ ... }
template<typename ValueT>
class Node : public NodeBase
{
...
};
NodeBase* ptr;
単純な答えは、C++が(かなり)厳密な静的型チェックを使用しているためです。 _Node<int>
_は_Node<double>
_とはまったく関係のない型であり、コンパイラがptr->doSomething()
を検出した場合、Node<int>::doSomething()
とNode<double>::doSomething()
のどちらを呼び出すかを知る必要があります。
実際の型ptr
が指す動的な汎用性が必要な場合は、実行時にしかわからないため、基本クラスを定義し、そこから派生させる必要があります。 (クラステンプレートが非テンプレートベースから派生することは、ごく一般的なイディオムであり、正確にポインタの一般性を実行時に解決できるようにします。)
まだクラスを作成していないポインターを宣言するときに型を指定する必要があるのはなぜですか、コンパイラーはそれが指す型を知る必要があるのはなぜですか。
ポインタを使用して実行できることはたくさんありますが、ごく一部を挙げます。
コンパイラーがこれらを効率的に行うコードを生成するには、ポインターのタイプを知っている必要があります。ポインターのタイプがわかるまで決定を延期した場合、次のいずれかを行う必要があります。
そして、汎用ポインタを作成して、後で割り当てるタイプを決定することはできません。
種類...多くのオプションがあります:
void*
を使用しますが、指す型を再び意味のある形で操作する前に、手動でその型にキャストし直す必要があります。あらゆる可能性boost::any<>
を使用-void*
とほぼ同じですが、安全性が組み込まれていますboost::variant<>
を使用-より安全で便利ですが、ポインタを作成するときに、参照される可能性のある型をリストする必要がありますNode
へのポインターがあります特定のタイプのノードを操作してから、テンプレート化されたNode
クラスがその抽象Node
から派生し、タイプ固有の関数バージョンを実装します。これらは、virtual
関数を使用して、基本クラスへのポインターを介して呼び出されます。C++で任意の種類のオブジェクト(ポインターを含む)を作成するときは常に、オブジェクトの完全な型がわかっている必要があります。コードにはNode
のような型がないため、その型へのポインターのインスタンスを作成することはできません。コードをどのように設計および記述しているかを再考する必要があります。
Neil ButterworthとLuc Dantonの両方が指摘したように、Nodeは型ではないため、テンプレートです。はい、Nodeはクラステンプレートですが、ここではclassはテンプレートの種類を示しています。これを見る1つの方法:クラスとクラスのインスタンスがまったく異なるように、テンプレートとテンプレートのインスタンス化。これは、クラスであるNodeなどのテンプレートのインスタンス化です。クラステンプレートは、他の種類の獣です。