2016-08-26 9 views
6

Tôi đang trong quá trình tạo lớp vectơ và đang cố gắng tìm cách sử dụng lại số lượng mã tối đa cho các vectơ có kích thước khác nhau. Dưới đây là một ví dụ cơ bản:Chuyển cấu trúc tạm thời làm đối số mẫu

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

Tôi muốn các biến thành viên để có thể truy cập công khai. Ví dụ:

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

Những gì tôi muốn làm là một cái gì đó dọc theo dòng này:

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

và có nó ghi đè lên một struct trong đoàn:

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

Có bất kỳ cách khả thi để làm điều này? Tôi không muốn sử dụng bất cứ thứ gì ngoài thư viện chuẩn nếu có thể. Cảm ơn trước.

EDIT: Sau khi đọc tất cả các câu trả lời, tôi hiểu rằng cách tôi đang sử dụng công đoàn không chính xác! Cảm ơn bạn @ M.M đã chỉ ra điều này. Tôi đã chọn để đi một con đường khác, nhưng tôi đã chọn câu trả lời phù hợp nhất với những gì tôi đang tìm kiếm vào thời điểm đó. Một lần nữa, cảm ơn bạn vì tất cả các phản hồi được hoan nghênh dưới đây!

+1

bạn có thực sự muốn * * để vượt qua các cấu trúc trong cho 'Vector' hay làm bạn chỉ muốn một cách để xác định Vector2/3/4 tạo ra kết quả cuối cùng? Lớp này dường như không hữu ích cho các kích thước> 6-8. Ngoài ra bạn không muốn 'T (0)' trong ctor của bạn, bạn muốn 'T {}' để mặc định khởi tạo nó. – kfsone

+3

Không hoàn toàn chắc chắn những gì bạn đang làm, nhưng lưu ý rằng trong C++ chỉ thành viên được chỉ định gần đây nhất của một công đoàn có thể được đọc; ví dụ. không được phép ghi vào 'v' rồi đọc từ' x'. –

+1

Điều gì @MM cho biết thực sự quan trọng! Không sử dụng 'union' để" chuyển đổi "một giá trị khác. Hãy xem xét 'std :: tuple' và quá tải của' operator [] 'để đạt được những gì bạn muốn làm – Garf365

Trả lời

1

Nếu tôi hiểu bạn một cách chính xác của bạn mục đích chính là để khai báo thứ tự các trường tương ứng với các phần tử mảng của lớp templated. Bạn không thể làm điều này trực tiếp vì các mẫu không chấp nhận kiểu nội tuyến làm tham số. Để workaround vấn đề bạn có thể chơi với những người không kiểu mẫu thông số để ràng buộc một số nhãn để chỉ số nhất định của một mảng:

#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

Điều bạn đang cố gắng làm là không được phép.
Dù sao, bạn có thể làm điều này:

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

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

Hoặc này:

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

Trong trường hợp thứ hai, Vector có thể được định nghĩa là:

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

    // ... 

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

Loại không phải là loại ở đâu? Các tham số mẫu không kiểu nào phải làm gì với điều này? – aschepler

+0

@aschepler Trong một số terns bạn là đúng. Đó không phải là loại lớp hay loại không phải lớp.Tôi đang xóa phần đầu tiên của câu trả lời, tôi sẽ để lại ở đó các giải pháp thay thế. – skypjack

2

Nó không quy mô rất tốt để một lớn D, nhưng nếu bạn chỉ sau các 5:56 biến tôi tưởng tượng, bạn có thể từng phần chuyên biệt hoá một lớp cơ sở:

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

Live Demo: http://ideone.com/T3QHoq

Các vấn đề liên quan