2

n 次元のデータセットを分析するコードを書いています。任意のデータセットの軸を表すクラスを作成しました。すべての軸は異なるデータ型を持つことができるため、テンプレート プログラミングを使用することにしました。

class BaseAxis
{
};

template <class T>
class Axis : public BaseAxis
{
public:
    Axis(const T &begin, const T &end);

    const T begin;
    const T end;
};

これにより、任意の型の新しい Axis オブジェクトを作成できます。ユーザーは、次のように正しい軸を追加することで、データセット全体を表すより高レベルのクラス NTree を構成できます。

ntree = new ntree::NTree<float>();
ntree->AddAxis<int>(0, 8);
ntree->AddAxis<float>(-100.0f, 200.0f);

これにより、0 から 8 までの範囲の整数軸と -100.0f から 200.0f までの範囲の浮動小数点軸を持つ 2 次元の浮動小数点データセットが作成されます。データセットから値を取得するには、次のようにデータ構造を照会できる必要があります。

ntree->Query(2, 2.5f);

私は現在、そのような関数 (またはこれらのパラメーターを表すことができるオブジェクト) を作成する方法を見つけようとしています。boost::variant について読んだことがありますが、c++ テンプレートとライブラリの経験が十分でないため、この場合にこれを適用する方法がわかりません。

NTree クラスのコードの関連部分を次に示します。

template <class T>
class NTree
{
public:
    NTree();
    ~NTree();

    template <class A>
    void AddAxis(const A &start, const A &end);

protected:
    std::vector<BaseAxis*> *axes;
};

template <class T>
template <class A>
void NTree<T>::AddAxis(const A &start, const A &end)
{
    BaseAxis* newAxis = new Axis<A>(start, end);
    this->axes->push_back(newAxis);
}

したがって、私の質問は次のとおりです。任意の長さと型の組み合わせの値のセットを表す方法は?

4

1 に答える 1

1

Typelistまたはvariadic templatesを使用してコンテナーを定義できます。このようにして、不透明なコンテナーを使用せずに強力な型の安全性を維持できます。おそらくバッファをコピーするという犠牲を払って、コンテナから軸を追加してリモートにすることができます。

そのためのクリーンな実装では、各タイプに専用のアロケーターを使用し、それらを集約するプロキシ クラスを使用できます。次に、パラメーターを使用してアロケーターをキャストし、アクセス関数を呼び出す、テンプレート化されたアクセサーをプロキシ クラスに含めることができます。

これは、N 次元コンテナーの (非常に切り捨てられた) 実装です。この場合、ボリュームは同じ次元で異なるタイプの配列のリストによって定義されるため、正確には必要なものではありませんが、閉じます。

 // opaque base class for allocator
 class UnsafeAllocator{...};

 // specialized allocator:
 template<class T>
 class Allocator : public UnsafeAllocator {
      ...
      virtual T& operator[] (const size_t * position) { ... }
 };

 // proxy class for the container:
 template<class TL>
 class Volume {
 protected:
     // each field has its own allocator, allocated in the constructor
     UnsafeAllocator *opaque_allocator[Length<TL>::value];
 public:
     // put a constuctor with the current dimensions here and fill in the array of allocators using the typelist

     // typesafe getter
     template <int index> 
     typename TypeAt<TL, index>::Result &
     get(const std::initializer_list<size_t> &position){
           typedef typename TypeAt<TL, index>::Result FieldType;
           typedef Allocator<FieldType> SafeAllocator;
           SafeAllocator* allocator = dynamic_cast<SafeAllocator *>(opaque_allocator[index]);
           assert(allocator != NULL);
           return (*allocator)[position];
      }
  };

  // usage would be:
  typedef MakeTypeList(float, int, double) types;
  // define a two dimensional volume for each type
  Volume<types> volume({1024,1024});
  // example of typesafe access for the first type at position 0,0:
  float f = volume.get<0>({0,0});

この実装の主な欠点は、コンパイル時にすべての型リストを知る必要があることです。それがあなたの仕様の一部であるかどうかはわかりません。

そうでない場合、不透明なプロキシをどこでも使用せずに可変数の可変長型を持つコンテナーを持つ方法はないと思います。これにより、コードの読みやすさ (およびおそらく安全性) が損なわれます。

于 2013-03-19T18:33:37.100 に答える