c ++模板特化特定声明

时间:2015-01-06 16:43:27

标签: c++ templates

基本上,我要做的是构建一个Vector模板,它有两个参数:维度和变量类型。

template <typename Type, unsigned ElementCount>
class TVector
    {
    private:
    public:
        union
            {
            struct
                {
                Type X, Y, Z, W;
                };
            struct
                {
                Type Red, Green, Blue, Alpha;
                };
            Type Values[ElementCount];
            };
    }

一切正常,但您可能已经注意到,这仅适用于4元素向量,因为只有Values变量依赖于ElementCount。 ElementCount = 1仅声明X和红色,2声明Y和绿色,依此类推...... 所以,我想要的是根据ElementCount值声明其他变量。

有可能吗?我不这么认为,但无论如何都想确定。

我正在考虑单独声明整个联合并将其作为模板参数传递,但这很丑陋.... [/ p>

编辑: 该死。现在我想起了一些事情......构造函数又是怎样的呢?

参数计数取决于模板参数ElementCount ......如何做?

4 个答案:

答案 0 :(得分:1)

你可以通过部分专业化来实现。像

这样的东西
template<typename T, unsigned N>
struct S
{
    union
    {
        struct
        {
            T X, Y, Z, W;
        };

        struct
        {
            T Red, Green, Blue, Alpha;
        };

        T Values[N];
    };
};

template<typename T>
struct S<T, 1>
{
    union
    {
        struct
        {
            T X;
        };

        struct
        {
            T Red;
        };

        T Values[1];
    };
};

int main()
{
    using S1 = S<char, 1>;
    using S5 = S<char, 5>;

    std::cout << "sizeof(S1) = " << sizeof(S1) << '\n';
    std::cout << "sizeof(S5) = " << sizeof(S5) << '\n';
}

应打印

sizeof(S1) = 1
sizeof(S5) = 5

另外,例如。

S1 s1;
s1.Y = 0;

应该给出一个错误,即结构没有成员Y

是的,编写(或复制粘贴)的内容要多得多,但它应该可以解决您的问题。

答案 1 :(得分:0)

您不需要传递整个联合 - 只需要字段的结构和类型。我还在操作员中添加了一个语法糖 - &gt;所以,如果你不愿意,你不必参考.Names部分。

#include <iostream>

struct PointStruct {
    int X;
    int Y;
    int Z;
};

struct ColorStruct {
    int Red;
    int Green;
    int Blue;
    int Alpha;
};


template <typename Type, typename Struct>
class TVector
{
public:
    const static int LEN = sizeof(Struct) / sizeof(Type);
    union
        {
            Struct Names;
            Type Values[LEN];
        };
    Struct* operator->() { return &Names; }
    const Struct* operator->() const { return &Names; }
};

int main(int argc, const char** argv) {
    TVector < int, PointStruct > points;
    points.Names.X = 55;
    points.Names.Y = -67;
    points.Names.Z = 42;
    for (int x = 0; x < points.LEN; ++x) {
        std::cout << "points[" << x << "]: " << points.Values[x] << std::endl;
    }
    points.Values[1] = 135;
    std::cout << "points->Y: " << points->Y << std::endl;
    TVector < int, ColorStruct > colors;
    colors.Names.Red = 1;
    colors.Names.Green = 2;
    colors.Names.Blue = 3;
    colors.Names.Alpha = 4;
    for (int x = 0; x < colors.LEN; ++x) {
        std::cout << "colors[" << x << "]: " << colors.Values[x] << std::endl;
    }
}

使用g ++ 4.3我得到了

points[0]: 55
points[1]: -67
points[2]: 42
points->Y: 135
colors[0]: 1
colors[1]: 2
colors[2]: 3
colors[3]: 4

答案 2 :(得分:0)

我会避免在这个级别进行专业化,而是在联盟内部进行专业化:

template <typename T> struct X   { T x; };
template <typename T> struct XY  { T x, y; };
...

template <typename T, int Count>
struct CountToXYZWType {};
template <typename T> struct CountToXYZWType<T,1> { typedef X<T>  type; };
template <typename T> struct CountToXYZWType<T,2> { typedef XY<T> type; };
...

template <typename T, int Count>
struct TVector {
   union {
      typename CountToXYZWType<Count>::type;
      // similarly CountToColorType<Count> ...
      T values[Count];
   }
...

};

答案 3 :(得分:0)

好的,首先,非常感谢大家,感谢所有想法。我终于设法做了我想要的,使用你所建议的混合。

第二,让我解释一下。我想重写我的数学库。我基本上有一个2d,3d和4d向量的类。这是愚蠢的,因为大多数代码是相同的,所以我决定尝试重构使用模板。

我还有一个名为RGB的小类,另一个名为RGBA的原因显而易见:)。

因此,我开始使用模板进行冒险(我不是一个大粉丝,但主要是因为我无法理解它们。它们当然非常有用)。

所以,经过几次尝试失败,我改变了方法。最后的结果是所有上述和厨房同步的混合。一个小的味道,包括成员函数(我有一些麻烦),与命名成员变量的联合在这里可用:http://goo.gl/4Zlt20

现在,最后一个问题,如果我可以......

这一切都按照我想要的方式运作,但出于某种原因,我无法摆脱“this-&gt;”关于内联函数。任何人都可以解释原因吗?

感谢。