2017-02-02 4 views
1

私はvariadicパラメータでテンプレートクラスのセットを使用しようとしています。私はいくつかの選択肢があり、私が選ぶことができます。私のテンプレートが宣言されたり、定義される前に、私は現在、これらのプロトタイプを持っています:私はテンプレートに精通していますが、テンプレートで作業するときにバリデーショナルタイプに関する多くの経験をしていないので、彼らは現在、コンパイルしているすべての空のシェルです。Variadicのテンプレートパラメータパックは、型としてunsigned intsまたはsize_tのみを受け入れるようにしました。

template<typename ClassType, typename... Args> class MatrixReference; 
template<typename ClassType, typename... Args> class MatrixStorage; 
template<typename ClassType, typename... Args> class MatrixAllocation; 

私には、使用目的に応じてこれらのクラスを使用するユーザーエンド・クラスがあります。私は適切な行動を正確に定義された他のクラスを得るまでには、現在今の空のシェルです:

template<typename ClassType, typename... Args> 
class Matrix {  
}; 

上に示したプロトタイプからクラスの残りの部分は基本クラスから継承する上でユーザークラスとなるようコンテナがstd::vector<std::unique_ptr<MatrixBase>>またはstd::vector<shared_ptr<MatrixBase>>のようなコンテナがあり、ベクターにはリストされたプロトタイプの各タイプのうちの1つだけが含まれます。たとえばvector [0]にはMatrixStorageが含まれ、vector [1]にはMatrixReferenceが格納され、vector [2]にはMatrixAllocationが格納されます。これらのクラスのそれぞれは、その名前が示唆するように異なる責任を持ちます。ストレージクラスには、要素の生スタックコピーが含まれます。参照クラスは、それらのコピーを参照するために使用されます。割り当てクラスは、要素がヒープ上で宣言されたときに使用されます。基底クラスは次のようになります。

template <typename ClassType = void> 
class MatrixBase { 
protected: 
    MatrixBase(){} 
    virtual ~MatrixBase(){} 
}; // Matrix 

私もこのクラスは、単一の容器の中に別のクラスの型を格納することができるという目的を果たすが、何もしないような非テンプレートベースからそれらを継承について考えています。私は先に進んでこれを非テンプレート型に変更するかもしれませんが、今は派生型の慣習に従うためにそのまま使用しています。

私のクラステンプレートの宣言に:私は本当にここでそれらのうちの1つを使う必要があります。すべて同じパターンに従っているからですが、現在は空のシェルなので3つをすべて表示します。

// Stores All Of The Contents Of The Matrix 
template<typename ClassType, typename... Args> 
class MatrixStorage : public MatrixBase<ClassType> { 
}; // MatrixStorage  

// Used To Reference The Storage Class Of The Matrix 
template<typename ClassType, typename... Args> 
class MatrixReference : public MatrixBase<ClassType> { 
}; // MatrixReference 

// Used Only When User Wants To Create A Matrix On The Heap 
template<typename ClassType, typename... Args> 
class MatrixAllocation : public MatrixBase<ClassType> { 
}; // MatrixAllocation 

私が探している設計アプローチは、このクラスが使用される場合、第1のタイプは、それがint、float型、またはも行列がいずれかの格納するデータの種類が常にあるパターンに従っていることです他のユーザ定義型。これは、2×2を生成します

Matrix<float,2,2> mat2x2; // Default constructor making it empty 

山車の行列の大きさの

Matrix<int,3,3,3> mat3x3x3; 

これが生成されます:1のようなテンプレートをインスタンス化する場合ように、可変引数パラメータの使用が入ってくるところの次のパラメータがあります3x3x3整数の容積行列

したがって、可変的なテンプレート部分は常に+整数であり、最小要件はMatrix<type, 1>となります。これは、スカラーまたは単一の要素行列または1x1行列の意味になります。

これは私がいくつかのオプションを提示したところです。私は、次の

  • size_t型を使用することができます... N
  • 符号なし... D
  • 型名...Args

現在のところ、あなたが見ることができるように、最後の選択肢とともに宣言されています。

私は私のようなヘルパークラスを持ってどこパラメータパックを使用することを決定した場合::

template <typename ClassType,typename... Dimensions> 
class DimensionPack { 
public: 
    typename std::tuple<ClassType, std::tuple<Dimensions...> >::type Dim; 
    const unsigned int numarguments = sizeof...(Dimensions); 
}; 

を疑問になる。だから今主な質問が来ます同じ種類のVariadic Parameterを作る方法がありますか?具体的には、size_tまたはunsigned intですか?そうであれば、参考になるか、リファレンスリンクが役立つでしょう。私は検索して、これを助けてくれるのに似ている有用なものは見つけられませんでした。

size_tまたはunsigned intを使用する必要はありませんが、ヘルパーテンプレートを使用して、この方法で可変パラメータをパックして展開することができるようにしたいと思いましたが、実装する必要はありませんそれはそれぞれのクラスにあります。

ここには示していない2つの派生クラスもありますが、1つは画面にログを記録する際に使用され、もう1つはファイルの読み込みと解析、ファイルへの書き込みに使用されます。サイドノートとしても

:非常に大規模なデータセットまたは非常に大きなサイズの行列の場合:

template<typename ClassType, std::size_t bufferSize> 
class MatrixBuffer { 
    static std::vector<ClassType> matrixBuffer = std::vector<ClassType>().reserve(bufferSize); 
}; 

編集

私は追加するのを忘れ:私はまた、彼らのために使用するには、このヘルパークラスを持っていますこれは元々の質問ですが、もう少し明確にするために追加しています。私は、奇数か偶数かを調べるために各可変パラメータの値をテストする必要があります。偶数の場合は0、奇数の場合は1を格納するパラメータ量のベクトルに結果を格納します。これは、必要なベクトルを返すヘルパー関数に渡すことができたため、パラメータパックの使用に傾いている理由の1つです。

+1

'template 'を使用できない理由はありますか? –

+0

@AlexZywicki私は同様に考えていましたが、抽出してstd :: tupleに展開するためのヘルパークラスが簡単になるかどうかは分かりませんでした。 –

+0

@AlexZywicki Oh;私はほとんど忘れていましたが、行列の各次元が奇数か偶数かを調べる必要があります。だから単に 'std :: size_t ...を持つ代わりにそのパックのサイズのベクトルを生成するためにそれらをパラメータパックに格納し、偶数の場合は0、奇数の場合は1で充填する必要があります。私は先に進み、私の質問にその明快さを加えることができます。 –

答えて

2

std::size_t... Argstypename... Argsは同じではありません。第二は、種類代わりを期待しつつ、第1は、整数よう

Matrix<float,2,2> mat2x2; 

を期待します。あなたがstd::index_sequenceを使用することができ

template <std::size_t N> 
using size = std::integral_constant<std::size_t, N>; 

Matrix<float,size<2>,size<2>> mat2x2; 

一方:もちろん
、あなたがstd::integral_constantを使用することができますが、それはより冗長になるだろう

template<typename ClassType, std::size_t... Dims> 
class Matrix { 
    using Dimensions = std::index_sequence<Dims...>; 
}; 
+0

ええ、私はそれを理解しています。私は、パラメータ・パックのヘルパー・テンプレート・クラスを使用して、パラメータ・リストをパックして解凍するのに役立つ 'std :: tuple'に内容を格納することに傾いています。また、これらのパラメータがx> 0の範囲にあるかどうかを確認し、それらが偶数か奇数かをテストし、その結果をコンテナに保存する必要があります。私はそれを私のヘルパー関数に渡すことができるでしょう... –

+0

これを見て、私はを使うことができますが、まだそれをstd :: tupleに保存します。同じヘルパークラスと関数。 –

+0

@FrancisCugler 'std :: index_sequence'を解凍する際の問題は何ですか? –

1

static_assertを使用して、コンパイル時にチェックすることが可能ですtime:

template <typename ClassType,typename... Dimensions> 
class DimensionPack { 
     public: 
      DimensionPack(const Dimensions&... args){ 
       checkType<Dimensions...>(args...); 
      } 
      ~DimensionPack(){} 
     private: 
      template<typename T> void checkType(const T& t) { 
       static_assert(std::integral_constant<bool, std::is_same<T, size_t>::value>(), "T is not of type size_t"); 
      } 
      template<typename T, typename... V> void checkType(const T& t, const V&... v) { 
       static_assert(std::integral_constant<bool, std::is_same<T, size_t>::value>(), "T is not of type size_t"); 
       checkType<V...>(v...); 
      } 
    }; 
関連する問題