2016-08-26 20 views
6

Bir vektör sınıfı oluşturma sürecindeyim ve farklı boyut vektörleri için maksimum kod miktarını yeniden kullanma yollarını bulmaya çalışıyorum.Şablon değişkeni olarak geçici yapı geçme

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]; } 
}; 

ben üye değişkenler herkese açık olacak şekilde istiyorum: Burada temel bir örnek. Ör:

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; }> {}; 

ve birlik içinde bir yapı geçersiz adres:

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

var mı ben yapmak istiyorum ne

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

bu çizgisinde bir şeydir Bunu yapmanın herhangi bir yolu var mı? Mümkünse standart kütüphaneden başka bir şey kullanmak istemiyorum. Şimdiden teşekkürler.

EDIT: Tüm cevapları okuduktan sonra, sendikaları kullanma şeklimin yanlış olduğunu anladım! Bunu belirtmek için M.M'e teşekkür ederim. O zamandan beri farklı bir rotaya gitmeyi seçtim, ama o zaman aradığım şeyi en iyi şekilde karşılayan cevabı seçtim. Bir kez daha, tüm memnuniyetle karşıladığınız cevaplar için teşekkür ederim!

+1

aslında * * Vector' 'için yapı geçmesi veya yapmak ister misiniz Son sonucu üreten Vector2/3/4'ü tanımlamanın bir yolunu mu istiyorsunuz? Bu sınıf> 6-8 bedenler için çok yararlı olacak gibi görünmüyor. Ayrıca, sizde 'T (0) 'istemiyorsanız,' T {}' varsayılanını başlatmak istersiniz. – kfsone

+3

Yaptıklarınızdan tam olarak emin değilsiniz, fakat C++ 'da sadece birliğin en son atanan üyesinin okunabileceğini unutmayın; Örneğin. 'v' yazmasına izin verilmez, daha sonra x 'den okunur. –

+1

What @ MM'nin söylediği gerçekten önemli! Bir değeri diğerine "dönüştürmek" için "sendika" kullanmayın. Ne yapmak istediğinizi başarmak için 'std :: tuple' ve operatörün aşırı yüklenmesine göz atın – Garf365

cevap

1

senin temel amaç, şablonlu sınıfın dizi elemanlarına karşılık gelen alanların sırasını bildirmek idi. Şablonlar satır içi türünü parametre olarak kabul etmediği için bunu doğrudan yapamazsınız. Eğer hemen sonra eğer

#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

Ne yapmaya çalışıyorsunuz izin verilmiyor.
Neyse, bunu yapabilirsiniz:

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

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

Ya da bu: İkinci durumda

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

, Vector olarak tanımlanabilir: seni doğru anladıysam

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

    // ... 

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

Sınıf dışı bir yazı türü nerede? Tipik olmayan şablon parametreleri bununla ne ilgisi var? – aschepler

+0

@aschepler Bazı tavalarda haklısınız. Bu ne bir sınıf türü ne de sınıf dışı bir tip.Cevabın ilk bölümünü siliyorum, yine de alternatif çözümleri orada bırakacağım. – skypjack

2

Büyük bir D çok iyi ölçek değildir, ancak: Eğer sigara tip şablon parametreleri ile oynayabilir sorun Bir dizinin verilen endekse bazı etiketleri bağlamak Geçici çözüm için benim hayal ettiğim dört ila altı varyantlar, bir temel sınıf kısmi uzmanlaşmak olabilir:

#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; 
} 

Canlı tanıtım: http://ideone.com/T3QHoq