2

他の言語(Java)との特定の違いを理解したかったという理由だけで、C ++テンプレートの使用を開始し、それらが分岐し始めたが、特定の問題を解決する方法がわかりません(またはそれを回避する)。

ジェネリック値クラスがあるとします。

template <class T>
class Value
{
  protected:
    T value;

  public:
    Value(Type type, T value) : type(type), value(value) {}

    void set(T value) { this->value = value; }
    T get() const { return this->value; }
    T clone() { return new Value<T>(type, value); }

    virtual string svalue() const = 0;

    const Type type;
};

および特定のサブタイプ:

class Int : public Value<int>
{
  public:  
    Int(int value) : Value<int>(INT, value) { };

    virtual string svalue() const { ... }

  friend ostream& operator<<(ostream& os, const Int& v);
};

(を使用して型固有のコードを指定することも可能ですtemplate <>が、それを理解するにはまだ十分に使用する必要があるため、今のところ、独自のIntクラスで定義しました。これはValue<int>、最終的にはtypedefにすぎません)

Valueたとえば、インスタンスへの任意のポインタを格納できるコレクションを持つことは可能ですか?ジェネリッククラスの特定の具象型を指定する必要はありません。

私が理解していることから、テンプレートはコンパイル時の問題であり、コンパイラはテンプレートが使用されるすべての具体的なタイプを分析し、それぞれに対して同じメソッドの異なるバージョンをコンパイルします。したがって、私がやろうとしていることはしません。可能のようです(Javaでは、のようなものにワイルドカードを使用できますList<Value<?>>)。私が間違っている?

この問題を解決するための一般的な設計はありますか、それともそれを達成するためにテンプレートを削除する必要がありますか?

4

5 に答える 5

3
#include <iostream>
#include <memory>

class Base 
{
    public: virtual void Print() = 0;
};

template<typename T>
class Derived : public Base
{
    T V;
public:
    void Print() { std::cout << V; }
    Derived(T v) : V(v) { }
};

int main()
{
    std::unique_ptr<Base> Ptr (new Derived<int>(5));
    Ptr->Print();

    return 0;
}

それはかなり自明だと思います。

于 2012-12-21T16:07:28.787 に答える
2

たとえば、Valueインスタンスへの任意のポインタを格納できるコレクションを持つことは可能ですか?

いいえ、あなたが望むようにではありません。これは不可能です:

template <class T>
class Value
{
// ...
};

vector<Value> my_values_;

Value はタイプではないため、これは不可能です。実際には、単なる青写真であり、必要に応じてアイデアです。哲学的なとりとめのない話はさておき、アイデアを保存することはできません。保存できるのは物事だけです。AValueは問題ではありません。

これが必要な場合は、テンプレートがジョブにとって間違ったツールである可能性があります。class Valueあなたが本当に求めているかもしれない小麦は、基本クラス(たとえば、 )がインターフェースを定義し、サブクラス(たとえば、class Int : public Value)が具象型を定義する抽象基本クラスです。Valueこのようにして、ポインタを使用してジェネリックのコンテナを作成できます。

vector<Value*> my_values_;

または、スマートポインタを使用する方がよいでしょう。

vector<unique_ptr<Value>> my_values_;
于 2012-12-21T16:11:41.777 に答える
1

Java手法は、一般的な基本クラス(Bartekによる他の回答を参照)と型消去などの手法を組み合わせてC++で実行できます。

値が実際に値であるC++バージョンは、Javaでは実行できません。正しく思い出せば、Javaバイトコードにコンパイルされるいくつかの言語で実行できます。

Javaでは、取得できる唯一のオブジェクトは、実際にはC++のオブジェクトへのガベージコレクションされたポインタのようなものです。直接保存または参照される実際のオブジェクトの実際のインスタンスは、Javaスタイルのガベージコレクションの邪魔になるため、verbotinです。

したがって、Javaのコンテナは、C++でガベージコレクションされるValue<?>すべてのタイプの共通基本クラスへのポインタのコンテナに類似しています。Value各インスタンスへのアクセスには、Javaのdynamic_castまたはstatic_cast同等のものが含まれます。

よりJava風の動作を実現するには、仮想トリビアルデストラクタを備えた共通ベース、すべてのインスタンスで同じシグネチャを持つ純粋な仮想共通メソッド、異なるシグネチャを持つものを実装するテンプレートバージョン、およびshared_ptrstoValueインスタンスを生成するファクトリ関数をValueに与えます。

のコンテナをshared_ptrValueベースに使用し、動的共有ptrキャストを使用して、必要に応じて特定のインターフェイスを取得します。

つまり、コードはその構造がない場合よりも10倍から100倍遅くなりますが、同等のJavaバージョンよりも高速である可能性があります。そして、あなたはそれを必要としないならそれを使わないという選択肢があります。

于 2012-12-21T16:30:31.910 に答える
1

私はいつも問題を混乱させ、素晴らしい構文のひねりを加えるのが大好きですが、それでも同じことをします (共通の基底クラスを使用します)。唯一の奇妙な点は、 の基本クラスValue<T>が綴られてValue<>おり、コンテナー内でそのまま使用できることです (もちろん、スライスを避けるためにポイントを使用する必要があるため、直接ではありません)。

#include <memory>
#include <vector>

template <typename T = void>
class Value;

template <>
class Value<void>
{
public:
    virtual ~Value() {}
};

template <typename T>
class Value
    : public Value<>
{
    T value_;
public:
    Value(T value): value_(value) {}
    // whatever
};

template <typename T>
std::unique_ptr<Value<T>> make_value(T value) {
    return std::unique_ptr<Value<T>>(new Value<T>(value));
}

int main()
{
    std::vector<std::unique_ptr<Value<>>> values;
    values.push_back(make_value(0));
    values.push_back(make_value(0.0));
    values.push_back(make_value(false));
}
于 2012-12-21T19:20:48.557 に答える
0

たとえば、Value インスタンスへの任意のポインターを格納できるコレクションを持つことは可能ですか?

いいえ、うまくいきません。ただし、少なくとも次の可能性があります。

  1. リストで使用するすべてのタイプが事前にわかっている場合は、boost::variantを使用できます

  2. オブジェクトへのポインターのリストを作成し (実際にはvoid*、またはテンプレートをドロップしValueて基本クラスとして作成することもできます)、何らかの形で (たとえばdynamic_cast) それらを特定のオブジェクトにキャストすることができます。

于 2012-12-21T16:13:54.767 に答える