首页 > 解决方案 > 固定数量的参数包元素来初始化模板类

问题描述

一般的想法是有一个通用类来表示n维空间中的一个点(“类Point”)。只要它们的类型相同,它就应该采用任意数量的参数。我使用可变参数模板参数包做到了这一点,它似乎工作正常。

现在我想要一个简单的别名,比如“Point2i”,它一次只接受整数参数(简单,只需指定类型 T)和两个参数(提示二维空间)(这是我到目前为止失败的地方) .

/**
 * @brief Point in n-dimensional space.
 */
template <typename T = int> class Point {
public:
    /**
     * @brief Default constructor for an empty polygon.
     * Points have to be added manually via @ref add_point.
     */
    template <typename... Ts>
    Point(Ts... coords) {
        m_coordinates = { std::forward<Ts>(coords)... };
    }

    /**
     * @brief Dimensions of the point coordinate space.
     * @return Number of dimensions.
     */
    size_t dims() const {
        return m_coordinates.size();
    }

    /**
     * @brief Array subscript operator.
     * @param dim The dimension you want.
     * @return The coordinate in the specified dimension.
     */
    T& operator[] (const size_t &dim) {
        return m_coordinates[dim];
    }

private:
    /// Coordinates of the point in n-dimensional space, where n = vector size.
    std::vector<T> m_coordinates;
};

template <typename... Ts, typename = typename std::enable_if<sizeof...(Ts) == 2>::type>
using Point2i = Point<int>(Ts...);

问题出在最后两行:“Point2i”的东西不起作用。我从 GCC 9 得到的错误是:“point.h:52:23: error: template parameter pack must be the last template parameter”。

第 52 行是带有“模板”的行

知道如何按照我想要的方式进行这项工作吗?我想对于有 C++ 模板元编程经验的人来说这很容易。

标签: c++templatesvariadic-templates

解决方案


我认为using对于类的构造函数来说这是不可能的。

我能想象的最好的是一个经典的make_something()功能。

我的意思是……有点像

template <typename... Ts,
          typename = typename std::enable_if<sizeof...(Ts) == 2>::type>
Point<int> Point2i (Ts... ts)
 { return { ts... }; }

Off Topic Unrequested Suggestion 1:尽可能使用构造函数初始化列表;避免(如果可能)在构造函数体内进行初始化

我的意思是...而不是

template <typename... Ts>
Point(Ts... coords) {
    m_coordinates = { std::forward<Ts>(coords)... };
}

更好

template <typename... Ts>
Point (Ts ... coords) : m_coordinates { std::forward<Ts>(coords)... }
 { }

Off Topic Unrequested 建议2:如果要使用完美转发,请使用转发引用。

所以构造函数变成

template <typename... Ts>
Point (Ts && ... coords) : m_coordinates { std::forward<Ts>(coords)... }
 { } //   ^^ <-- add forwarding references

也在point2i函数中

template <typename... Ts,
          typename = typename std::enable_if<sizeof...(Ts) == 2>::type>
Point<int> Point2i (Ts && ... ts) 
 { return { std::forward<Ts>(ts)... }; }

Off Topic Unrequested Suggestion 3:我想你的Point对象是固定大小的。在这种情况下,我建议考虑将点的大小添加为模板参数的假设。这样您就可以使用std::array而不是std::vector.


推荐阅读