2016-08-26 8 views
6

私はベクトルクラスを作成中ですが、異なるサイズのベクトルに対して最大量のコードを再利用する方法を見つけようとしています。一時的な構造体をテンプレート引数として渡す

template<typename T, unsigned int D> 
class Vector 
{ 
public: 
    union { 
     T v[D]; 
     struct { 
      /* T x; 
      * T y; 
      * T z; 
      * T w; 
      */ 
     }; 
    }; 

    Vector() 
    { 
     for(unsigned int i=0; i<D; ++i) 
      (*this)[i] = T(0); 
    } 
    Vector(T scalar) 
    { 
     for(unsigned int i=0; i<D; ++i) 
      (*this)[i] = scalar; 
    } 

    inline T operator[](int i) { return (*this).v[i]; } 
}; 

私はメンバ変数をパブリックにアクセス可能にしたい: ここで基本的な例です。例:

template<typename T> 
class Vector2 : public Vector<T,2, struct { T x; T y; }> {}; 

template<typename T> 
class Vector3 : public Vector<T,2, struct { T x; T y; T z; }> {}; 

、それが労働組合で構造体オーバーライドしています:

template<typename T, unsigned int D, struct C> 
class Vector 
{ 
public: 
    union { 
     T v[D]; 
     // Place the passed struct here 
    }; 
}; 

はありますが、私が何をしたいのですがどのような

Vector<float,2> vec; 
printf("X: %.2f, Y: %.2f\n", vec.x, vec.y); 

本の線に沿って何かでありますこれを行う実現可能な方法?可能であれば標準ライブラリ以外のものを使用したくない。前もって感謝します。

編集:すべての回答を読んだ後、私は組合を使用している方法が間違っていることを理解しました!これを指摘してくれてありがとう@M。私は以来、別のルートを選択していますが、私はその時に探していたものに最も適した答えを選択しました。もう一度、以下のすべての歓迎された回答に感謝します!

+1

は、あなたが実際に* * Vector' 'の中で構造体を渡すか、何をしたいですか最終結果を生成するVector2/3/4を定義する方法がほしいだけですか?このクラスは、> 6-8のサイズでは非常に便利なようではありません。また、 'T(0)'をあなたのctorに入れたくない場合は、 'T {}'がデフォルトで初期化されるようにします。 – kfsone

+3

あなたが何をしているのかはまだ分かりませんが、C++では最も最近割り当てられた組合員だけが読むことができます。例えば'v'に書き込み、' x'から読み込むことは許されません。 –

+1

@MMが言ったことは本当に重要です!値を別のものに「変換」するために「共用体」を使用しないでください。あなたは何をしたいのかを達成するために 'std :: tuple'と' operator [] 'のオーバーロードを見てください – Garf365

答えて

1

あなた主な目的は、テンプレートクラスの配列要素に対応するフィールドの順序を宣言することでした。テンプレートはインラインタイプをパラメータとして受け入れないため、これを直接行うことはできません。あなたは、配列の指定されたインデックスにいくつかのラベルをバインドするために非型テンプレートパラメータで遊ぶことができ、問題回避するには:

#include <cstdio> 
#include <unordered_map> 
#include <utility> 

struct Label { } x, y, z, w; 

template <Label&... labels> 
struct Pack { }; 

template <class, class> 
struct VectorParent; 

template <Label&... labels, size_t... Is> 
struct VectorParent<Pack<labels...>, std::index_sequence<Is...>> { 
    static std::unordered_map<Label *, size_t> label_map; 
}; 

template <Label&... labels, size_t... Is> 
std::unordered_map<Label *, size_t> VectorParent<Pack<labels...>, std::index_sequence<Is...>>::label_map = {{&labels, Is}...}; 

struct LabelNotFound { }; 

template <class T, size_t N, Label&... labels> 
struct Vector:VectorParent<Pack<labels...>, std::make_index_sequence<sizeof...(labels)>> { 
    static_assert(N == sizeof...(labels), 
     "the cound of labels should corespond to the number of elements of the vector"); 
    using VectorParent<Pack<labels...>, std::make_index_sequence<sizeof...(labels)>>::label_map; 
    T t[N]; 
    T &operator->*(Label& l) { 
     auto it = label_map.find(&l); 
     if (it == label_map.end()) 
     throw LabelNotFound{}; 
     return t[it->second]; 
    } 
}; 

int main() { 
    Vector<float,2,x,y> vec; 
    vec->*x = 10.0f; 
    printf("X: %.2f, Y: %.2f\n", vec->*x, vec->*y); // prints: X: 10.00, Y: 0.00 
    //vec->*w = 10.1f; //would throw an exception LabelNotFound 
} 
4

あなたがしようとしていることは許可されていません。
とにかく、あなたがこれを行うことができます:

template<typename T> 
struct S { T x; T y; }; 

template<typename T> 
class Vector2 : public Vector<T,2,S<T>> {}; 

またはこの:第2のケースで

template<typename T> 
class Vector2 : public Vector<T,2,S> {}; 

を、Vectorは次のように定義することができます:私が正しくあなたを理解している場合

template<typename T, unsigned int D, template<typename> class S> 
class Vector { 
    using MyStruct = S<T>; 

    // ... 

    union { 
     T v[D]; 
     MyStruct myStruct; 
    }; 
}; 
+0

非クラス型はどこですか?非型テンプレートパラメータはこれと何が関係がありますか? – aschepler

+0

@ascheplerあなたは正しいです。これはクラス型でも非クラス型でもありません。私は答えの最初のセクションを削除しています。とにかく代替ソリューションを残しておきます。 – skypjack

2

をこれは、大規模なDに非常にうまくスケールしませんが、あなただけの後にしている場合私が想像してる4〜6変異体は、あなたは、基本クラスを部分特化ができます

#include <iostream> 

template<typename T, size_t D> 
struct VectorBase; 

template<typename T> 
struct VectorBase<T, 2> 
{ 
    constexpr VectorBase() : v{} {} 
    union { 
     T v[2]; 
     struct { T x, y; }; 
    }; 
}; 

template<typename T> 
struct VectorBase<T, 3> 
{ 
    constexpr VectorBase() : v{} {} 
    union { 
     T v[3]; 
     struct { T x, y, z; }; 
    }; 
}; 

template<typename T> 
struct VectorBase<T, 4> 
{ 
    constexpr VectorBase() : v{} {} 
    union { 
     T v[4]; 
     struct { T x, y, z, w; }; 
    }; 
}; 

template<typename T, size_t D> 
struct Vector : public VectorBase<T, D> 
{ 
    using VectorBase<T, D>::v; 
    using size_type = decltype(D); 
    using value_type = T; 

    constexpr Vector() : VectorBase<T,D>{} {} 
    constexpr Vector(T scalar) { 
     std::fill(std::begin(v), std::end(v), scalar); 
    } 

    constexpr T& operator[](size_type i) const noexcept { return v[i]; } 
    constexpr const T& operator[](size_type i) noexcept { return v[i]; } 

    constexpr size_type size() const noexcept { return D; } 

    constexpr T* data() noexcept { return &v[0]; } 
    constexpr const T* data() const noexcept { return &v[0]; } 
}; 

template<typename T> 
using Vector2 = Vector<T, 2>; 
template<typename T> 
using Vector3 = Vector<T, 3>; 
template<typename T> 
using Vector4 = Vector<T, 4>; 

int main() { 
    Vector3<int> v{1}; 

    std::cout << v[0] << ", " << v.z << "\n"; 
    return 0; 
} 

ライブデモ:http://ideone.com/T3QHoq

関連する問題