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

7

我想创建一个通用的向量类,并为一些情况创建特殊化。就像这样(它不能编译,但希望能够传达我的意图):

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,并且在dim = 2的情况下具有x()y()访问器方法,在dim = 3的情况下具有x()y()z()。 我对错误消息有点困惑:

vector.h:56:10: error: declaration of ‘int dim’

vector.h:6:10: error: shadows template parm ‘int dim’

< p >(< code >T< / code >同样如此)。

请问怎样才能正确完成这个任务?(如果可能的话)
3个回答

12

1.

部分特化模板时,只提供实际是参数的模板参数。由于您已经将 dim 固定为 2 或 3,因此无需再指定它。

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

2.

专门化一个类实际上意味着更改整个声明。因此,泛型 Vector<dim, T> 的成员 s 在专门化的 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();
}

关于第二点,请求澄清。您的文本中写道:“您可以将通用的Vector<dim,T>作为私有基类...”,但示例代码使用了“public”基类。这是故意的还是意外的?我认为这两种情况都很有趣和值得探讨——部分模板特化的私有、保护和公共继承。 - kevinarpe
@kevinarpe:我指的是一个“内部”的基类,它不应该直接在库外被引用(已编辑)。基类需要是公共的,否则其中的所有方法都无法在类外访问。 - kennytm
我认为可以使用私有或保护继承,但需要使用“using”语句将成员的访问权限提升为公共。 - kevinarpe

3
部分特化应该像这样:

部分特化应该像这样:

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

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

4
在14.5.5/1中: "一个特化的模板参数列表不得包含默认模板参数值。" - fefe

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中编译(不要运行它...)。

但是,以此方式,您将无法在特化中使用任何主模板中定义的成员变量或成员函数。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接