问题描述
这里的C++新手:我想创建一个模板类来创建不同数据类型和class UploadFileForm(forms.ModelForm):
def __init__(self,*args,**kwargs):
super(UploadFileForm,self).__init__(*args,**kwargs)
self.fields['file'].label = 'Choose your file'
class Meta:
model = File
fields = ('file',)
widgets = {
'file': forms.FileInput(attrs={'id': 'upload-file','class': 'custom-upload'})
}
def index(request):
return render(request,"homepage/index.html",{ "form": UploadFileForm() })
维度的张量,其中d
由形状指定。例如,形状为 d
的张量有 3 个维度,可容纳 24 个元素。我使用一维向量存储所有数据元素,并希望使用形状信息访问元素以查找元素。
我想覆盖 (2,3,5)
运算符以访问元素。由于维度可能会有所不同,因此 ()
运算符的输入参数数量也会有所不同。从技术上讲,我可以使用向量作为输入参数,但 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,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,4};
Tensor<float> tensor(data,shape);
tensor(2,3); // <-- What I would like to do
// Possible workaround with vector which I would like to avoid
// std::vector<std::size_t> index = {2,3};
// tensor(index);
使用可变参数函数覆盖 tensor2.hpp:27:33: error: expansion pattern ‘std::size_t&’ {aka ‘long unsigned int&’} contains no parameter packs
运算符的正确方法是什么?
解决方法
您可以添加具有多个重载的辅助函数,以计算访问项目的正确索引:
T& getData(int dim1) { return m_data[dim1];}
T& getData(int dim1,int dim2) { return m_data[ dim1* m_shape[1] + dim2 ];}
T& getData(int dim1,int dim2,int dim3) { return m_data[ dim1*m_shape[1]*m_shape[2] + dim2*m_shape[2] + dim3 ];}
然后 operator()
可能看起来像:
template<class ... Args>
T& operator()(Args... d_args) {
static_assert( (std::is_integral_v<Args> && ...) ); // [1]
return getData(d_args...);
}
通过 [1] 我们限制 ()
仅用于整数类型。
通过提供“形状”作为模板参数,您可以:
// Helper for folding to specific type
template <std::size_t,typename T> using always_type = T;
// Your Tensor class
template <typename T,std::size_t... Dims>
class MultiArray
{
public:
explicit MultiArray(std::vector<T> data) : values(std::move(data))
{
assert(values.size() == (1 * ... * Dims));
}
const T& get(const std::array<std::size_t,sizeof...(Dims)>& indexes) const
{
return values[computeIndex(indexes)];
}
T& get(const std::array<std::size_t,sizeof...(Dims)>& indexes)
{
return values[computeIndex(indexes)];
}
const T& get(always_type<Dims,std::size_t>... indexes) const
{
return get({{indexes...}});
}
T& get(always_type<Dims,std::size_t>... indexes)
{
return get({{indexes...}});
}
static std::size_t computeIndex(const std::array<std::size_t,sizeof...(Dims)>& indexes)
{
constexpr std::array<std::size_t,sizeof...(Dims)> dimensions{{Dims...}};
size_t index = 0;
size_t mul = 1;
for (size_t i = dimensions.size(); i != 0; --i) {
assert(indexes[i - 1] < dimensions[i - 1]);
index += indexes[i - 1] * mul;
mul *= dimensions[i - 1];
}
assert(index < (1 * ... * Dims));
return index;
}
static std::array<std::size_t,sizeof...(Dims)> computeIndexes(std::size_t index)
{
assert(index < (1 * ... * Dims));
constexpr std::array<std::size_t,sizeof...(Dims)> dimensions{{Dims...}};
std::array<std::size_t,sizeof...(Dims)> res;
std::size_t mul = (1 * ... * Dims);
for (std::size_t i = 0; i != dimensions.size(); ++i) {
mul /= dimensions[i];
res[i] = index / mul;
assert(res[i] < dimensions[i]);
index -= res[i] * mul;
}
return res;
}
private:
std::vector<T> values; // possibly: std::array<T,(1 * ... * Dims)>
};
用法类似于
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};
MultiArray<float,4> tensor(data);
std::cout << tensor.get(1,3); // 16