【问题标题】:Mixing partial template specialization and default template parameters混合部分模板特化和默认模板参数
【发布时间】:2011-12-27 13:20:11
【问题描述】:

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

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() 访问器方法,以及x()y()z() 用于 dim = 3 案例。我对错误消息有点困惑:

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

vector.h:6:10: 错误:阴影模板参数“int dim”

T 相同)。

我怎样才能正确地做到这一点? (如果可能的话)

【问题讨论】:

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


    【解决方案1】:

    1.

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

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

    2.

    专门化一个类实际上意味着改变整个声明。因此,通用Vector&lt;dim, T&gt; 的成员s 在专用Vector&lt;2, T&gt; 中将不可用。您可以将通用 Vector&lt;dim, T&gt; 作为内部基类,并创建一个仅用于专业化的子类:

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

    【讨论】:

    • 关于#2,要求澄清。您的文字内容为:You could make the generic Vector&lt;dim, T&gt; as into a private base class... 示例代码使用public 基类。这是故意的还是偶然的?我想这两种情况实际上都很有趣且值得——private vs protected vs public 部分模板专业化的继承。
    • @kevinarpe:我的意思是一个“内部”基类,它不应该直接从库中引用(已编辑)。基类必须是公共的,否则其中的所有方法都无法在类外访问。
    • 我认为可以使用私有或受保护的继承,但需要using 语句才能将成员的访问权限“提升”为公共。
    【解决方案2】:

    部分特化应该是这样的:

    template <int Dim, typename T = float> class Vector; // primary
    
    template <typename T> class Vector<2, T> { /* ... */ };
    template <typename T> class Vector<3, T> { /* ... */ };
    

    【讨论】:

    • 在 14.5.5/1 中:“专业化的模板参数列表不应包含默认模板参数值。”
    【解决方案3】:

    你可以这样做:

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

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2013-09-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-07-16
      相关资源
      最近更新 更多