web-dev-qa-db-ja.com

テンプレートクラスポインターC ++宣言

template <typename T>
class Node
{...};

int main
{
    Node* ptr;
    ptr = new Node<int>;
}

コンパイルに失敗します私はポインタを次のように宣言する必要があります

Node<int>* ptr;

まだクラスを作成していないポインターを宣言するときに型を指定する必要があるのはなぜですか、コンパイラーはそれが指す型を知る必要があるのはなぜですか。そして、汎用ポインタを作成して、後で割り当てるタイプを決定することはできません。

17
randomBananas

テンプレート化は、コンパイル時に型を解決します。新しいNode<int>オブジェクトを割り当てる場合、ポインターはコンパイル時にそれが正確にどの型であるかを知っている必要があります。

Node<int>Node<std::vector>は、バイナリ(テンプレートパラメーターに応じてオブジェクトのバイナリレイアウトが完全に変化する)で大きく異なる可能性があるため、テンプレートへの未解決のポインター型を指定しても意味がありません。

まず、ノードの共通の親クラスを定義する必要があります。

class NodeBase
{ ... }

template<typename ValueT>
  class Node : public NodeBase
{
 ...
};

NodeBase* ptr;
30
progician

単純な答えは、C++が(かなり)厳密な静的型チェックを使用しているためです。 _Node<int>_は_Node<double>_とはまったく関係のない型であり、コンパイラがptr->doSomething()を検出した場合、Node<int>::doSomething()Node<double>::doSomething()のどちらを呼び出すかを知る必要があります。

実際の型ptrが指す動的な汎用性が必要な場合は、実行時にしかわからないため、基本クラスを定義し、そこから派生させる必要があります。 (クラステンプレートが非テンプレートベースから派生することは、ごく一般的なイディオムであり、正確にポインタの一般性を実行時に解決できるようにします。)

9
James Kanze

まだクラスを作成していないポインターを宣言するときに型を指定する必要があるのはなぜですか、コンパイラーはそれが指す型を知る必要があるのはなぜですか。

ポインタを使用して実行できることはたくさんありますが、ごく一部を挙げます。

  • ポインタのタイプに基づいて多くの関数の1つを呼び出す
  • それからのインデックス(そのようなオブジェクトの連続した配列の最初の要素を指すと仮定して)
  • 指し示されたオブジェクトのサイズを取る
  • ポインタ型がパラメータであるテンプレートにそれを渡します

コンパイラーがこれらを効率的に行うコードを生成するには、ポインターのタイプを知っている必要があります。ポインターのタイプがわかるまで決定を延期した場合、次のいずれかを行う必要があります。

  • ポインターが後で取る可能性のあるすべてのタイプに対して効率的なコードをコンパイルする(巨大なプログラムを作成する)、または
  • いくつかの最悪のケースの悲観的な不器用な振る舞いを通じて可能なすべての型を処理できる非効率的なコードを作成する、または
  • それ自体(コンパイラー)のコピーをC++プログラムに埋め込むと、必要な情報が得られたときにその仕事を完了することができます。これにより、すべての簡単なプログラムが巨大になります(そして遅くなります)。

そして、汎用ポインタを作成して、後で割り当てるタイプを決定することはできません。

種類...多くのオプションがあります:

  • void*を使用しますが、指す型を再び意味のある形で操作する前に、手動でその型にキャストし直す必要があります。あらゆる可能性
  • boost::any<>を使用-void*とほぼ同じですが、安全性が組み込まれています
  • boost::variant<>を使用-より安全で便利ですが、ポインタを作成するときに、参照される可能性のある型をリストする必要があります
  • オブジェクトのランタイムポリモーフィックファミリーと仮想ディスパッチを使用します...これは古典的なオブジェクト指向プログラミングです...使用する共有関数とメンバーデータを宣言する「抽象」Nodeへのポインターがあります特定のタイプのノードを操作してから、テンプレート化されたNodeクラスがその抽象Nodeから派生し、タイプ固有の関数バージョンを実装します。これらは、virtual関数を使用して、基本クラスへのポインターを介して呼び出されます。
5
Tony Delroy

C++で任意の種類のオブジェクト(ポインターを含む)を作成するときは常に、オブジェクトの完全な型がわかっている必要があります。コードにはNodeのような型がないため、その型へのポインターのインスタンスを作成することはできません。コードをどのように設計および記述しているかを再考する必要があります。

1
user2100815

Neil ButterworthとLuc Dantonの両方が指摘したように、Nodeは型ではないため、テンプレートです。はい、Nodeはクラステンプレートですが、ここではclassはテンプレートの種類を示しています。これを見る1つの方法:クラスとクラスのインスタンスがまったく異なるように、テンプレートとテンプレートのインスタンス化。これは、クラスであるNodeなどのテンプレートのインスタンス化です。クラステンプレートは、他の種類の獣です。

1
David Hammen