将临时结构作为模板参数传递

时间:2016-08-26 19:22:06

标签: c++ templates struct

我正在创建一个矢量类,并试图找出为不同大小的矢量重用最大代码量的方法。 这是一个基本的例子:

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

我希望成员变量可以公开访问。例如:

Vector<float,2> vec;
printf("X: %.2f, Y: %.2f\n", vec.x, vec.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; }> {};

并让它覆盖union中的结构:

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

有没有可行的方法呢?如果可能的话,我不想使用标准库以外的任何东西。提前谢谢。

编辑:在阅读完所有答案后,我了解到我使用工会的方式不正确!感谢@ M.M指出这一点。我已经选择了不同的路线,但我选择了最适合我当时寻找的答案。再次感谢下面的所有欢迎回复!

3 个答案:

答案 0 :(得分:4)

不允许您尝试做什么 无论如何,你可以这样做:

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

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

或者这个:

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

答案 1 :(得分:2)

它不能很好地扩展到大D,但是如果你只是在我想象的四到六个变体之后,你可以对基类进行局部特化:

#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

答案 2 :(得分: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
}