動機
using Vector4 = TVector<float, 4>; Vector3 a = Vector3(0.0f, 1.0f, 0.0f, 1.0f); Vector4 b = Vector4(2.0f, 3.0f, 0.0f, 1.0f); Vector4 c = Vector4(a.XY(), b.XY()); Vector4 d = Vector4(a, 10.0f);
templateを使用した
ベクトルクラスを作ったのですが、
↑のような書き方を実現しようとすると
template<class Type, uint32_t N> class TVector { private; Type v[N]; }; // コンストラクタ template<class Type, uint32_t N> inline TVector<Type, N>::TVector(const Type x) : v() { for (uint32_t i = 0; i < N; i++) { v[i] = x; } } template<class Type, uint32_t N> inline TVector<Type, N>::TVector(const Type x, const Type y) : v() { static_assert(N >= 2, ""); v[0] = x; v[1] = y; } template<class Type, uint32_t N> inline TVector<Type, N>::TVector(const Type x, const Type y, const Type z, const Type w) : v() { static_assert(N >= 4, ""); v[0] = x; v[1] = y; v[2] = z; v[3] = w; } template<class Type, uint32_t N> template<uint32_t I> inline TVector<Type, N>::TVector(const TVector<Type, I>& vec0) : v() { // Vector4 = Vector3 // Vector3 = Vector4 const uint32_t count = (I > N) ? N : I; for (uint32_t i = 0; i < count; i++) { v[i] = vec0.At(i); } } template<class Type, uint32_t N> template<uint32_t I, uint32_t J, uint32_t K, uint32_t L> inline TVector<Type, N>::TVector(const TVector<Type, I>& vec0, const TVector<Type, J>& vec1, const TVector<Type, K>& vec2, const TVector<Type, L>& vec3) : v() { static_assert(N >= I + J + K + L, ""); uint32_t index = 0; for (uint32_t i = 0; i < I; i++) { v[i] = vec0.At(i); } index += I; for (uint32_t i = 0; i < J; i++) { v[index + i] = vec1.At(i); } index += J; for (uint32_t i = 0; i < K; i++) { v[index + i] = vec2.At(i); } index += K; for (uint32_t i = 0; i < L; i++) { v[index + i] = vec3.At(i); } }
といった感じで一つ一つコンストラクタを書いていかないといけない。(長いので一部消してます。)
これが色々と面倒くさいので、短く実装したい。
実装
void Expansion(size_t& index) { } template<typename Head, typename... Tail> void Expansion(size_t& index, Head&& head, Tail&&... tail) { if (index >= N) return; constexpr size_t ByteSize = sizeof(head); constexpr size_t TypeSize = sizeof(Type); constexpr size_t Count = (ByteSize / TypeSize); const Type* data = (Type*)(&head); for (size_t i = 0; i < Count; i++) { if (index >= N) return; v[index++] = data[i]; } Expansion(index, tail...); } template<typename... Args> TVector(Args... args) { size_t index = 0; Expansion(index, args...); }
実装しました。
Expansion関数でパラメータパックを展開してます。
やっていることは、引数のバイト数から配列の数を調べて
アドレスのデータを渡しているだけです。
めちゃくちゃ短くなってすっきりしました。
使い方を覚えるとめちゃめちゃ便利だなぁー