1

いくつかのインフラストラクチャコードをリファクタリングしようとして、いくつかのクラス間でポリモーフィックな動作を実現するために継承を使用することにしました。次のステップは、それらをコンテナーにスローし、それらとDoSomething()を反復処理することです。

私の現在のコンテナの構造は不器用です。このエレガントなソリューションをコンテナに使用しても、構造はまだ混乱しています。

vector<unique_ptr<Parent>> vec;

vec.push_back(unique_ptr<Parent>(new ChildA(var1, var2)));
vec.push_back(unique_ptr<Parent>(new ChildB(var3, var4)));
vec.push_back(unique_ptr<Parent>(new ChildC(var5, var6)));

ChildA、ChildB、およびChildCは、すべて互いに多形です。Var1 ... var6はさまざまなタイプのものである可能性があり、子オブジェクトの構築に必要です。

このベクトルをいくつかの場所で作成して使用したいと思います。問題は、子供の数が変化する可能性があるため、子供が建設に必要なデータが異なることです。stdarg.hのパスを歩こうとすると、サポートされていないため失敗しました。

if     !defined(_WIN32)
#error ERROR: Only Win32 target supported!
#endif

この配列を構築するファクトリメソッドをどのように実装しますか?

更新、望ましい解決策:

vec = CreatePolyVec(var1, var2, typeInfo1, var3, var4, typeInfo2, var5, var6 typeInfo3);
vec = CreatePolyVec(var1, var2, typeInfo1, var3, var4, typeInfo2);

1行目は、上記と同じ配列を作成します。2行目では、同じコードを再利用して同様のベクトルを作成しますが、オブジェクトは1つ少なくなります。Typeinfoは、オブジェクトの作成に必要な情報を保持します。

これは基本的な解決策であり、より高度な解決策では、コンパイル時に引数リストが適用されます。たとえば、次の関数の呼び出しは意味がありません。

vec = CreatePolyVec(var1, var2,typeinfo1, var3, var4, typeinfo2, var5);

最後の子オブジェクトを作成するのに十分なパラメータがありません。

4

2 に答える 2

4

ここには2つの問題があります。1。各子のタイプを決定する方法、および2.複数の子を作成する方法。

作成する子を決定するには

これは、コンパイル時または実行時に実行できます。コンパイル時にこれを行うには、テンプレートが必要です。

template<class Child, class Arg1, class Arg2>
vector<unique_ptr<Parent>> CreateVec(Arg1&& arg1, Arg2&& arg2)
{
    vector<unique_ptr<Parent>> result;
    result.push_back(unique_ptr<Child>(
        new Child(std::forward<Arg1>(arg1), std::forward<Arg2>(arg2))));
    return result;
}

次のように呼ばれますCreateVec<MyChild>(myArg1, myArg2)

実行時に決定する必要がある場合は、実行時変数によってインデックス付けされたファクトリ関数のマップを使用できます。または、ファクトリオブジェクトへのポインタを実行時変数として使用することもできます。

複数の子を作成するには

ここでは、連鎖関数と可変個引数テンプレートのどちらかを選択できます。

連鎖機能

これは本質的にiostreamsが行うことです。ベクトルを作成して1つの子を追加する関数に、2番目の子を追加できるオブジェクトを返し、それ自体を返して続行できるようにします。

ここでの問題は、関数がベクトルを返すようにしたいので、別のオブジェクトを返すこともできないということです。変換演算子を使用してベクトルまたは明示的な関数を取得できますが、おそらく最初にベクトルを作成し、関数を使用して子を追加するのが最も簡単です。

class AddChildren
{
    vector<unique_ptr<Parent>>& m_vector;
public:
    explicit AddChildren(vector<unique_ptr<Parent>>& theVector)
        : m_vector(theVector) {}

    template<class Child, class Arg1, class Arg2>
    AddChildren& add(Arg1&& arg1, Arg2&& arg2)
    {
        m_vector.push_back(unique_ptr<Child>(
            new Child(std::forward<Arg1>(arg1), std::forward<Arg2>(arg2))));
        return *this;
    }
};

次のように使用されます。

vector<unique_ptr<Parent>> myvector;
AddChildren(myvector)
    .add<ChildA>(var1, var2)
    .add<ChildB>(var3, var4)
    .add<ChildC>(var5, var6);

使用できるタイプを選択する実行時の方法を使用operator()していて、次のようになっている場合:

vector<unique_ptr<Parent>> myvector;
AddChildren(myvector)
    (childAType, var1, var2)(childBType, var3, var4)(childCType, var5, var6);

(これは、子タイプごとに特定のタイプセレクタータイプのダミーオブジェクトをパラメーターとして使用することにより、コンパイル時にタイプを選択することでも実行できます。)

可変個引数テンプレートの使用

可変個引数テンプレートを使用して、一度に3つのパラメーターをはがし、子オブジェクトを追加します。

void addChildren(vector<unique_ptr<Parent>>& theVector)
{}

template<class FirstChild, class FirstArg1, class FirstArg2, class... Rest>
void addChildren(vector<unique_ptr<Parent>>& theVector,
    FirstChild childtype, FirstArg1&& arg1, FirstArg2&& arg2, Rest&&... rest)
{
    addChild(theVector, childtype,
        std::forward<Arg1>(arg1), std::forward<Arg2>(arg2));
    addChildren(theVector, std::forward<Rest>(rest)...);
}

template<class... Args>
vector<unique_ptr<Parent>> CreateVec(Args&&... args)
{
    vector<unique_ptr<Parent>> result;
    addChildren(result, std::forward<Args>(args)...);
    return result;

}

ここではaddChild、型(パラメーターとして)と引数を指定して子を追加できる関数の存在を想定しています。

これに関する主な問題は、VS2012に可変個引数テンプレートがないことです。可変個引数テンプレートをシミュレートする方法は2つあります。1.必要になる可能性のあるパラメーターの最大数を取り、それらのほとんどを「存在しない」という意味で取ることができる既知のタイプにデフォルト設定する単一の関数を記述します。2.必要と思われる数のオーバーロードを書き出します。

子オブジェクトを10個以上必要としないことがわかっている場合、2番目のオプションは実際には完全に実行可能です。1回だけ記述する必要があり、おそらく150行未満のコードです。または、Boost.Preprocessorを使用して関数を生成することもできますが、これはまったく新しいレベルの複雑さです。

于 2013-01-09T14:47:19.047 に答える
2

2012年11月のコンパイラの更新により、VS 2012は可変個引数テンプレートをサポートするため、次のように機能するはずです(これは、求めている構文ではありませんが、かなり近いと思います)。

struct VectorCreator
{
  explicit VectorCreator(std::vector<Parent> &vec)
    : vec_(vec)
  {}

  template <typename Type, typename... ArgType>
  VectorCreator& create(ArgType&&... arg)
  {
    vec_.push_back(std::unique_ptr<Parent>(new Type(std::forward<ArgType>(arg)...));
    return *this;
  }

private:
  std::vector<Parent> &vec_;
};

このように使用します:

std::vector<Parent> vec;
VectorCreator(vec).create<ChildA>(var1, var2).create<ChildB>(var3, var4).create<ChildC>(var5, var6);
于 2013-01-09T14:37:50.017 に答える