【问题标题】:Variadic template parameter pack to accept only unsigned ints or size_t as its type可变参数模板参数包仅接受无符号整数或 size_t 作为其类型
【发布时间】:2017-02-02 03:47:40
【问题描述】:

我正在尝试使用一组带有可变参数的模板类。我有几个选项可供我选择。在我的任何模板被声明或定义之前,我目前拥有这些原型:我熟悉模板,但在使用模板时我没有太多使用可变参数类型的经验,因此有时语法确实让我有点困惑。因为它们都是空壳,所以它们目前正在编译。

template<typename ClassType, typename... Args>  class MatrixReference;
template<typename ClassType, typename... Args>  class MatrixStorage;
template<typename ClassType, typename... Args>  class MatrixAllocation;

我有一个用户端类,它将根据使用意图使用这些类;在我使用适当的行为正确定义其他类之前,它目前是一个空壳:

template<typename ClassType, typename... Args>
class Matrix {      
};

上面显示的原型中的其余类将继承自一个基类,因此上面的用户类将拥有它们的容器,容器将是:std::vector&lt;std::unique_ptr&lt;MatrixBase&gt;&gt; 或std::vector&lt;shared_ptr&lt;MatrixBase&gt;&gt;,并且向量将只曾经包含列出的原型中的每种类型的 1 个。例如,vector[0] 将包含一个 MatrixStorage,vector[1] 将包含一个 MatrixReference,vector[2] 将包含一个 MatrixAllocation。顾名思义,这些类中的每一个都有不同的职责。存储类将包含元素的原始堆栈副本。引用类将用于引用这些副本。当在堆上声明元素时将使用分配类。基类如下所示:

template <typename ClassType = void>
class MatrixBase {
protected:
    MatrixBase(){}
    virtual ~MatrixBase(){}
}; // Matrix

我还考虑过从非模板基类继承它们,因为这个类除了用于将不同的类类型存储到单个容器中之外什么都不做。我可能会继续将其更改为非模板类​​型,但现在我按原样使用它以保持其派生类型的约定。

现在开始我的类模板的声明:我真的只需要在这里使用其中一个,因为它们都遵循相同的模式,但无论如何我都会展示所有 3 个,因为它们目前是空壳。

// Stores All Of The Contents Of The Matrix
template<typename ClassType, typename... Args>
class MatrixStorage : public MatrixBase<ClassType> {
}; // MatrixStorage    

// Used To Reference The Storage Class Of The Matrix
template<typename ClassType, typename... Args>
class MatrixReference : public MatrixBase<ClassType> {
}; // MatrixReference

// Used Only When User Wants To Create A Matrix On The Heap
template<typename ClassType, typename... Args>
class MatrixAllocation : public MatrixBase<ClassType> {
}; // MatrixAllocation

我正在寻找的设计方法是,当使用此类时,它遵循以下模式:第一个类型始终是矩阵将存储的数据类型,它可以是 int、float 或其他用户定义的类型;下一个参数是使用可变参数的地方,因此如果将模板实例化为这样:

Matrix<float,2,2> mat2x2; // Default constructor making it empty

这将生成一个 2x2 大小的浮点矩阵

Matrix<int,3,3,3> mat3x3x3; 

这将生成一个 3x3x3 体积矩阵的整数

因此,可变参数模板部分将始终为 + 整数,最低要求为 Matrix&lt;type, 1&gt;,在某种意义上,这将是标量或单元素矩阵或 1x1 矩阵。

这是为我提供几个选项的地方。我可以使用以下

  • size_t...N
  • 未签名... D
  • 类型名称... Args

目前你可以看到它是用最后一个选项声明的。那么现在主要问题来了:

如果我决定使用我有一个辅助类的参数包:

template <typename ClassType,typename... Dimensions>
class DimensionPack {
public: 
    typename std::tuple<ClassType, std::tuple<Dimensions...> >::type Dim;
    const unsigned int numarguments = sizeof...(Dimensions);
};

问题变成了;有没有一种已知的方法可以制作相同类型的可变参数,即size_t 或unsigned int?如果是这样,一个例子将不胜感激,或者参考链接也会有所帮助;我进行了搜索,但没有发现任何足以帮助我解决此问题的有用信息。

如果没有,我不介意使用size_t 或unsigned int,但我更喜欢能够使用帮助模板为我打包和解包可变参数,我不这样做必须在每个班级中实现这一点。

我还有 2 个其他派生类,此处未显示,但其中一个用于将它们记录到屏幕上,另一个用于从文件读取和解析以及写入文件。

另外作为旁注:对于非常大的数据集或非常大的矩阵:我也有这个帮助类供他们使用:

template<typename ClassType, std::size_t bufferSize>
class MatrixBuffer {
    static std::vector<ClassType> matrixBuffer = std::vector<ClassType>().reserve( bufferSize );
};

编辑

我忘记将其添加到原始问题中,但我现在添加它是为了更清楚一点。我确实需要测试每个可变参数的值以查看它是奇数还是偶数,它们的结果将存储到一个向量中,该向量的大小与存储偶数为 0 或奇数为 1 的参数数量相同。这是我倾向于使用参数包的原因之一,因为我可以将它传递给一个帮助函数,该函数将返回所需的向量。

【问题讨论】:

  • 你有什么理由不能只使用template&lt;typename ClassType, std::size_t... Args&gt;?
  • @AlexZywicki 我也是这么想的,但不确定用于提取和扩展为 std::tuple 的辅助类是否会使事情变得更容易。
  • @AlexZywicki 哦;我差点忘了,但我确实需要检查矩阵的每个维度是奇数还是偶数。因此,不仅仅是让std::size_t... 将它们存储到参数包中以生成该包大小的向量,并用 0 表示偶数或 1 表示奇数,这也是需要的。我可以继续为我的问题添加清晰的内容。
  • 所以,答案是没有充分的理由不使用size_t...Args。你走错了路。
  • @FrancisCugler 动态分配来存储编译时间常数似乎是个坏主意,但不是我的猴子,不是我的马戏团。

标签: c++ variadic-templates stdtuple


【解决方案1】:

std::size_t... Args 和 typename... Args 不一样。第一个期望整数喜欢

Matrix<float,2,2> mat2x2;

而第二个则需要 types。
当然,你可以使用std::integral_constant,但这样会更冗长:

template <std::size_t N>
using size = std::integral_constant<std::size_t, N>;

Matrix<float,size<2>,size<2>> mat2x2;

另一方面,您可以使用std::index_sequence:

template<typename ClassType, std::size_t... Dims>
class Matrix {
    using Dimensions = std::index_sequence<Dims...>;
};

【讨论】:

  • 是的,我明白;但我倾向于使用仅用于参数包的帮助模板类将内容存储到std::tuple 中,这将有助于打包和解包参数列表。我还需要检查这些参数以查看它们是否在 x > 0 范围内,并测试它们是偶数还是奇数,并将这些结果保存到容器中。然后我就可以将它传递给我的辅助函数......
  • 或者我是不是在看这个......我可以在哪里使用 <:size_t...> 但仍然将它保存到相同的辅助类和函数中的 std::tuple 中。
  • @FrancisCugler 解压std::index_sequence有什么问题?
  • 不熟悉 index_sequence
  • 我不希望实例化看起来像这样:Matrix&lt;float, &lt;2&gt;, &lt;3&gt;&gt; 等。我更喜欢 Matrix&lt;type, value, value, value&gt;
【解决方案2】:

使用 static_assert 可以在编译时检查:

template <typename ClassType,typename... Dimensions>
class DimensionPack {
        public:
            DimensionPack(const Dimensions&... args){
                checkType<Dimensions...>(args...);
            }
            ~DimensionPack(){}
        private:
            template<typename T> void checkType(const T& t) {
                static_assert(std::integral_constant<bool, std::is_same<T, size_t>::value>(), "T is not of type size_t");
            }
            template<typename T, typename... V> void checkType(const T& t, const V&... v) {
                static_assert(std::integral_constant<bool, std::is_same<T, size_t>::value>(), "T is not of type size_t");
                checkType<V...>(v...);
            }
    };

【讨论】:

    猜你喜欢
    • 2011-04-15
    • 1970-01-01
    • 2021-03-29
    • 1970-01-01
    • 2011-07-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-11-22
    相关资源
    最近更新 更多