混合部分模板特化和默认模板参数

时间:2011-12-27 13:20:11

标签: c++ templates c++11 template-specialization

我想创建一个通用的矢量类,并为少数情况创建特化。像这样的东西(它不会编译,但希望能传达我的意图):

template<int dim, typename T = float>
class Vector
{
public:
    typedef Vector<dim, T> VecType;

    Vector() { /**/ }
    Vector(const VecType& other) { /**/ )
    Vector& operator=(const VecType& other) { /**/ }

    VecType operator+(const VecType& other) { /**/ }    
    VecType operator-(const VecType& other) { /**/ }    
    T operator*(const VecType& other) { /**/ }

private:
    std::array<T, dim> elements;
};

template<int dim, typename T>
class Vector<2>
{
public:
    T x() const { return elements[0]; }
    T y() const { return elements[1]; }
};

template<int dim, typename T>
class Vector<3>
{
public:
    T x() const { return elements[0]; }
    T y() const { return elements[1]; }
    T z() const { return elements[2]; }
};

换句话说,我希望元素的默认类型为float,我想为x()案例设置y()dim = 2访问器方法,并且x()案例的y()z()dim = 3。我对错误消息感到有些困惑:

  

vector.h:56:10:错误:'int dim'的声明

     

vector.h:6:10:错误:阴影模板parm'int dim'

T相同)。

我该如何正确地做到这一点? (如果可能的话)

3 个答案:

答案 0 :(得分:10)

1

当部分特化模板时,仅提供实际上是参数的模板参数。由于您已将dim修改为2或3,因此无需再次指定。

template<typename T>
class Vector<2, T>
{
   ....

2

专业化一堂课真的意味着改变整个宣言。因此,通用Vector<dim, T>的成员将无法在专门的Vector<2, T>中使用。您可以将通用Vector<dim, T>作为内部基类,并为专门化创建子类:

template<int dim, typename T>
class VectorImpl;

...

template<int dim, typename T = float>
class Vector : public VectorImpl<dim, T> {};

template<typename T>
class Vector<2, T> : public VectorImpl<2, T>
{
public:
   T x() const { ... }
};

3

您无需定义VecType!在模板中,您可以使用Vector。它将自动推断出具有正确参数的类。

编译的最终结果:

#include <array>

template<int dim, typename T>
class VectorImpl
{
public:
    //typedef Vector<dim, T> VecType;

    VectorImpl() {  }
    VectorImpl(const VectorImpl& other) {  }
    VectorImpl& operator=(const VectorImpl& other) { return *this; }

    VectorImpl operator+(const VectorImpl& other) { return *this; }
    VectorImpl operator-(const VectorImpl& other) { return *this; }
    T operator*(const VectorImpl& other) { return 0; }

protected:
    std::array<T, dim> elements;
};

template <int dim, typename T = float>
class Vector : public VectorImpl<dim, T> {};

template<typename T>
class Vector<2, T> : public VectorImpl<2, T>
{
public:
    T x() const { return this->elements[0]; }
    T y() const { return this->elements[1]; }
};

template<typename T>
class Vector<3, T> : public VectorImpl<2, T>
{
public:
    T x() const { return this->elements[0]; }
    T y() const { return this->elements[1]; }
    T z() const { return this->elements[2]; }
};

int main()
{
    Vector<2> v;
    Vector<3> vv;
    v + v;
    vv.z();
}

答案 1 :(得分:2)

部分专业化应该是这样的:

template <int Dim, typename T = float> class Vector; // primary

template <typename T> class Vector<2, T> { /* ... */ };
template <typename T> class Vector<3, T> { /* ... */ };

答案 2 :(得分:0)

你可以这样做:

#include <array>
template<int dim, typename T = float>
class Vector
{
public:
    typedef Vector<dim, T> VecType;
    Vector() { /**/ }
    Vector(const VecType& other) { /**/ }
private:
    std::array<T, dim> elements;
};

template<typename T>
class Vector<2, T>
{
public:
    T x() const { return elements[0]; }
    T y() const { return elements[1]; }
private:
    std::array<T, 2> elements;
};

template<typename T>
class Vector<3, T>
{
public:
    T x() const { return elements[0]; }
    T y() const { return elements[1]; }
    T z() const { return elements[2]; }
private:
    std::array<T, 3> elements;
};

int main(int argc, char **argv)
{
    Vector<2> v2;
    v2.x();
    Vector<3> v3;
    v3.z();
    return 0;
}

这可以在gcc 4.5.2中编译(不要运行它......)。

但是,通过这种方式,您将无法在专业化的主模板中使用成员函数define的任何成员变量。