【发布时间】:2021-05-31 09:07:59
【问题描述】:
这里的C++新手:我想创建一个模板类来创建不同数据类型和d维度的张量,其中d由一个形状指定。例如,形状为(2, 3, 5) 的张量有 3 个维度,包含 24 个元素。我使用一维向量存储所有数据元素,并希望使用形状信息访问元素以查找元素。
我想覆盖() 运算符来访问元素。由于维度可以变化,() 运算符的输入参数数量也可以变化。从技术上讲,我可以使用向量作为输入参数,但 C++ 似乎也支持可变参数函数。但是,我无法理解它。
到目前为止我所拥有的:
#ifndef TENSOR_HPP
#define TENSOR_HPP
#include <vector>
#include <numeric>
#include <algorithm>
#include <stdexcept>
#include <iostream>
#include <stdarg.h>
template <typename T> class Tensor {
private:
std::vector<T> m_data;
std::vector<std::size_t> m_shape;
std::size_t m_size;
public:
// Constructors
Tensor(std::vector<T> data, std::vector<std::size_t> shape);
// Destructor
~Tensor();
// Access the individual elements
T& operator()(std::size_t&... d_args);
};
template <typename T> Tensor<T>::Tensor(std::vector<T> data, std::vector<std::size_t> shape) {
// Calculate number of data values based on shape
m_size = std::accumulate(std::begin(shape), std::end(shape), 1, std::multiplies<std::size_t>());
// Check if calculated number of values match the actual number
if (data.size() != m_size) {
throw std::length_error("Tensor shape does not match the number of data values");
}
// All good from here
m_data = data;
m_shape = shape;
}
template <typename T> T& Tensor<T>::operator() (std::size_t&... d_args) {
// Return something to avoid warning
return m_data[0];
};
template <typename T> Tensor<T>::~Tensor() {
//delete[] m_values;
};
#endif
当我执行以下操作时不会:
std::vector<float> data = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24};
std::vector<std::size_t> shape = {2, 3, 4};
Tensor<float> tensor(data, shape);
tensor(2,0,3); // <-- What I would like to do
// Possible workaround with vector which I would like to avoid
// std::vector<std::size_t> index = {2,0,3};
// tensor(index);
我得到错误:
tensor2.hpp:27:33: error: expansion pattern ‘std::size_t&’ {aka ‘long unsigned int&’} contains no parameter packs
使用可变参数函数覆盖() 运算符的正确方法是什么?
【问题讨论】:
-
Tensor<float, 2, 3, 4>怎么样? -
您的编译器不应允许您将纯右值作为具有非 const 限定引用类型的参数传递...
-
@Jarod42 以这种方式定义张量当然没问题。这将如何影响代码。同样,这应该是灵活的,因为我可能希望将 24 个值存储在
Tensor<float, 2, 12>、Tensor<float, 12, 2>、Tensor<float, 1, 1, 1, 1, 24>、Tensor<float, 1, 12, 1, 2>等中。假设这里会有一个变化template <typename T, ???> class Tensor,()运算符的定义是什么样的? -
术语:你想重载一个操作符,而不是覆盖(后者是一个非术语)。
-
如果形状是 {2,3,4} 并且您尝试访问 tensor(0,0),您希望发生什么?
标签: c++ variadic-templates variadic-functions