模板相关的构造函数参数长度

时间:2014-11-26 14:28:15

标签: templates c++11 constructor variadic-functions

我尝试制作一个通用但仍然高效的多维Point类。

我所拥有的是Dimensions enum

enum Dimension : std::size_t { _2D = 2, _3D = 3 };

Point class

template <typename T, Dimension D>
class Point : public std::array<T, D>
{
    public:
        T&        at(size_t idx)       { return std::array<T,D>::at(idx); };
        const T&  at(size_t idx) const { return std::array<T,D>::at(idx); };
        Dimension dim()          const { return D; }
        ...
};

我想创建nices构造函数,所以我添加了(在我的类定义之外)

template <typename T>
Point<T,_2D>::Point(T x, T y)      { at(0) = x; at(1) = y;            }
template <typename T>
Point<T,_3D>::Point(T x, T y, T z) { at(0) = x; at(1) = y; at(2) = z; }

但我仍然无法使用。编译器告诉我只注册了默认(空)和复制构造函数。

问题:

如何定义参数列表长度取决于我的Dimension模板的构造函数?

2 个答案:

答案 0 :(得分:1)

我会这样做,因为我懒得写同一件事的许多版本:

template<class T, Dimension D>
class Point : public std::array<T,D> {

    template<class... Args>
    Point(Args... vs) :
        std::array<T,D>{{vs...}}
    {
        static_assert(sizeof...(Args) == D, "wrong number of args");
    }

    ...

};

答案 1 :(得分:0)

有几种方法可以实现这一目标。在您的情况下,使用std::enable_if

可能最简单
template <typename T, Dimension D>
class Point : public std::array<T, D>
{
    public:
        template <
            Dimension D2=D,
            typename = typename std::enable_if<D2==_2D>::type
        >
        Point(T x,T y);

        template <
            Dimension D2=D,
            typename = typename std::enable_if<D2==_3D>::type
        >
        Point(T x,T y,T z);

        T&        at(size_t idx)       { return std::array<T,D>::at(idx); };
        const T&  at(size_t idx) const { return std::array<T,D>::at(idx); };
        Dimension dim()          const { return D; }
        ...
};

另一种选择是将其分解为多个类并使用专门化:

template <typename T, Dimension D>
class PointBase : public std::array<T, D>
{
    public:
        T&        at(size_t idx)       { return std::array<T,D>::at(idx); };
        const T&  at(size_t idx) const { return std::array<T,D>::at(idx); };
        Dimension dim()          const { return D; }
        ...
};

template <typename T, Dimension D> class Point;

template <typename T>
class Point<T,_2D> : public PointBase<T,_2D> {
    public:
        Point(T x,T y);
};

template <typename T>
class Point<T,_3D> : public PointBase<T,_3D> {
    public:
        Point(T x,T y,T z);
};