C++ 如何制作一个;可变的;类向量类
我试图使类充当多维向量。它不需要做任何花哨的事情。我基本上希望有一个“container”类foo,在这里我可以通过foo[x][y][z]访问元素。现在我还需要类似的foo[x][y]和foo[x]类。这让我思考了下面的(更一般的)问题,有没有一种方法可以让这样的东西,你可以对任意n个参数初始化为fooa(a,b,c,…),然后得到一个n维向量,其中的元素可以被[]访问。。。?下面是四维的例子 首先是标题C++ 如何制作一个;可变的;类向量类,c++,c++11,vector,variadic,C++,C++11,Vector,Variadic,我试图使类充当多维向量。它不需要做任何花哨的事情。我基本上希望有一个“container”类foo,在这里我可以通过foo[x][y][z]访问元素。现在我还需要类似的foo[x][y]和foo[x]类。这让我思考了下面的(更一般的)问题,有没有一种方法可以让这样的东西,你可以对任意n个参数初始化为fooa(a,b,c,…),然后得到一个n维向量,其中的元素可以被[]访问。。。?下面是四维的例子 首先是标题 #ifndef FCONTAINER_H #define FCONTAINE
#ifndef FCONTAINER_H
#define FCONTAINER_H
#include <iostream>
using namespace std;
class Fcontainer
{
private:
unsigned dim1, dim2, dim3, dim4 ;
double* data;
public:
Fcontainer(unsigned const dims1, unsigned const dims2, unsigned const dims3, unsigned const dims4);
~Fcontainer();
Fcontainer(const Fcontainer& m);
Fcontainer& operator= (const Fcontainer& m);
double& operator() (unsigned const dim1, unsigned const dim2, unsigned const dim3, unsigned const dim4);
double const& operator() (unsigned const dim1, unsigned const dim2, unsigned const dim3, unsigned const dim4) const;
};
#endif // FCONTAINER_H
所以我想把它扩展到任意数量的维度。我想这将需要一些变量模板或std::initializer_列表,但我不清楚如何解决这个问题 好吧,假设您关心效率,那么您可能希望以连续的方式存储所有元素。因此,您可能希望执行以下操作:
template <std::size_t N, class T>
class MultiArray {
MultiArray(const std::array<std::size_t, N> sizes)
: m_sizes(sizes)
, m_data.resize(product(m_sizes)) {}
std::array<std::size_t, N> m_sizes;
std::vector<T> m_data;
};
最后,当您完成最后一个索引时,您有一个专门化:
template <>
class Indexor<N-1> { // with obvious constructor
auto operator[](std::size_t index) {
m_indices[N-1] = index;
return m_parent.m_data[indexed_product(m_indices, m_parent.m_sizes)];
}
std::array<std::size_t, N> m_indices;
MultiArray& m_parent;
};
Edit2:我在实现中使用
product
和index\u product
。第一个是显而易见的,第二个不是那么明显,但希望它们应该是清楚的。后者是一个函数,给定一个维度数组和一个索引数组,它将返回该元素在数组中的位置。在Visual Studio中胡闹了一会儿,我想出了一个无稽之谈:
template<typename T>
class Matrix {
std::vector<size_t> dimensions;
std::unique_ptr<T[]> _data;
template<typename ... Dimensions>
size_t apply_dimensions(size_t dim, Dimensions&& ... dims) {
dimensions.emplace_back(dim);
return dim * apply_dimensions(std::forward<Dimensions>(dims)...);
}
size_t apply_dimensions(size_t dim) {
dimensions.emplace_back(dim);
return dim;
}
public:
Matrix(std::vector<size_t> dims) : dimensions(std::move(dims)) {
size_t size = flat_size();
_data = std::make_unique<T[]>(size);
}
template<typename ... Dimensions>
Matrix(size_t dim, Dimensions&&... dims) {
size_t size = apply_dimensions(dim, std::forward<Dimensions>(dims)...);
_data = std::make_unique<T[]>(size);
}
T & operator()(std::vector<size_t> const& indexes) {
if(indexes.size() != dimensions.size())
throw std::runtime_error("Incorrect number of parameters used to retrieve Matrix Data!");
return _data[get_flat_index(indexes)];
}
T const& operator()(std::vector<size_t> const& indexes) const {
if (indexes.size() != dimensions.size())
throw std::runtime_error("Incorrect number of parameters used to retrieve Matrix Data!");
return _data[get_flat_index(indexes)];
}
template<typename ... Indexes>
T & operator()(size_t idx, Indexes&& ... indexes) {
if (sizeof...(indexes)+1 != dimensions.size())
throw std::runtime_error("Incorrect number of parameters used to retrieve Matrix Data!");
size_t flat_index = get_flat_index(0, idx, std::forward<Indexes>(indexes)...);
return at(flat_index);
}
template<typename ... Indexes>
T const& operator()(size_t idx, Indexes&& ... indexes) const {
if (sizeof...(indexes)+1 != dimensions.size())
throw std::runtime_error("Incorrect number of parameters used to retrieve Matrix Data!");
size_t flat_index = get_flat_index(0, idx, std::forward<Indexes>(indexes)...);
return at(flat_index);
}
T & at(size_t flat_index) {
return _data[flat_index];
}
T const& at(size_t flat_index) const {
return _data[flat_index];
}
size_t dimension_size(size_t dim) const {
return dimensions[dim];
}
size_t num_of_dimensions() const {
return dimensions.size();
}
size_t flat_size() const {
size_t size = 1;
for (size_t dim : dimensions)
size *= dim;
return size;
}
private:
size_t get_flat_index(std::vector<size_t> const& indexes) const {
size_t dim = 0;
size_t flat_index = 0;
for (size_t index : indexes) {
flat_index += get_offset(index, dim++);
}
return flat_index;
}
template<typename ... Indexes>
size_t get_flat_index(size_t dim, size_t index, Indexes&& ... indexes) const {
return get_offset(index, dim) + get_flat_index(dim + 1, std::forward<Indexes>(indexes)...);
}
size_t get_flat_index(size_t dim, size_t index) const {
return get_offset(index, dim);
}
size_t get_offset(size_t index, size_t dim) const {
if (index >= dimensions[dim])
throw std::runtime_error("Index out of Bounds");
for (size_t i = dim + 1; i < dimensions.size(); i++) {
index *= dimensions[i];
}
return index;
}
};
模板
类矩阵{
向量维数;
std::唯一的ptr数据;
模板
尺寸应用尺寸(尺寸、尺寸和…尺寸){
尺寸:后安放(尺寸);
返回尺寸*应用尺寸(标准:前进(尺寸)…);
}
尺寸应用尺寸(尺寸尺寸){
尺寸:后安放(尺寸);
返回暗淡;
}
公众:
矩阵(标准::向量dims):尺寸(标准::移动(dims)){
尺寸=平面尺寸();
_数据=标准::使_唯一(大小);
}
模板
矩阵(尺寸、尺寸和…尺寸){
尺寸=应用尺寸(尺寸,标准::正向(尺寸)…);
_数据=标准::使_唯一(大小);
}
T运算符()(标准::向量常量和索引){
if(index.size()!=dimensions.size())
抛出std::runtime_错误(“用于检索矩阵数据的参数数量不正确!”);
返回数据[get_flat_index(索引)];
}
常量和运算符()(标准::向量常量和索引)常量{
if(index.size()!=dimensions.size())
抛出std::runtime_错误(“用于检索矩阵数据的参数数量不正确!”);
返回数据[get_flat_index(索引)];
}
模板
运算符()(大小\u T idx、索引和…索引){
if(sizeof…(索引)+1!=维度.size())
抛出std::runtime_错误(“用于检索矩阵数据的参数数量不正确!”);
size_t flat_index=get_flat_index(0,idx,std::forward(索引)…);
收益率(平指数);
}
模板
常量和运算符()(大小\u T idx、索引和…索引)常量{
if(sizeof…(索引)+1!=维度.size())
抛出std::runtime_错误(“用于检索矩阵数据的参数数量不正确!”);
size_t flat_index=get_flat_index(0,idx,std::forward(索引)…);
收益率(平指数);
}
T&at(尺寸扁平指数){
返回数据[平面索引];
}
T常数和at(尺寸扁平指数)常数{
返回数据[平面索引];
}
尺寸尺寸大小(尺寸)常数{
返回尺寸[dim];
}
大小\u t数量\u的维数()常数{
返回维度。size();
}
大小\u t扁平\u大小()常数{
尺寸=1;
用于(尺寸:尺寸)
尺寸*=暗;
返回大小;
}
私人:
大小获取平面索引(标准::向量常量和索引)常量{
尺寸尺寸=0;
尺寸指数=0;
用于(大小索引:索引){
平面索引+=获取偏移量(索引,dim++);
}
返回平面指数;
}
模板
大小获取平面索引(大小、大小索引、索引和…索引)常量{
返回get_偏移量(索引,dim)+get_平坦索引(dim+1,std::forward(索引)…);
}
大小获取平面索引(大小、大小索引)常量{
返回get_偏移量(索引,dim);
}
大小获取偏移量(大小索引、大小尺寸)常量{
如果(索引>=维度[dim])
抛出std::runtime_错误(“索引超出范围”);
对于(尺寸i=dim+1;i
让我们来谈谈这段代码实现了什么
//private:
template<typename ... Dimensions>
size_t apply_dimensions(size_t dim, Dimensions&& ... dims) {
dimensions.emplace_back(dim);
return dim * apply_dimensions(std::forward<Dimensions>(dims)...);
}
size_t apply_dimensions(size_t dim) {
dimensions.emplace_back(dim);
return dim;
}
public:
Matrix(std::vector<size_t> dims) : dimensions(std::move(dims)) {
size_t size = flat_size();
_data = std::make_unique<T[]>(size);
}
template<typename ... Dimensions>
Matrix(size_t dim, Dimensions&&... dims) {
size_t size = apply_dimensions(dim, std::forward<Dimensions>(dims)...);
_data = std::make_unique<T[]>(size);
}
//私有:
模板
尺寸应用尺寸(尺寸、尺寸和…尺寸){
尺寸:后安放(尺寸);
返回尺寸*应用尺寸(标准:前进(尺寸)…);
}
尺寸应用尺寸(尺寸尺寸){
尺寸:后安放(尺寸);
返回暗淡;
}
公众:
矩阵(标准::向量dims):尺寸(标准::移动(dims)){
尺寸=平面尺寸();
_数据=标准::使_唯一(大小);
}
模板
矩阵(尺寸、尺寸和…尺寸){
尺寸=应用尺寸(尺寸,标准::正向(尺寸)…);
_数据=标准::使_唯一(大小);
}
这段代码使我们能够为这个矩阵编写一个初始值设定项,它具有任意数量的维度
int main() {
Matrix<int> mat{2, 2}; //Yields a 2x2 2D Rectangular Matrix
mat = Matrix<int>{4, 6, 5};//mat is now a 4x6x5 3D Rectangular Matrix
mat = Matrix<int>{9};//mat is now a 9-length 1D array.
mat = Matrix<int>{2, 3, 4, 5, 6, 7, 8, 9};//Why would you do this? (yet it compiles...)
}
intmain(){
矩阵mat{2,2};//产生一个2x2二维矩形矩阵
mat=矩阵{4,6,5};//mat现在是4x6x5三维矩形矩阵
mat=矩阵{9};//mat现在是一个9长度的1D数组。
mat=矩阵{2,3,4,5,6,7,8,9};//为什么要这样做?(但它编译了…)
}
如果只有在运行时才知道维度的数量和大小
template<typename T>
class Matrix {
std::vector<size_t> dimensions;
std::unique_ptr<T[]> _data;
template<typename ... Dimensions>
size_t apply_dimensions(size_t dim, Dimensions&& ... dims) {
dimensions.emplace_back(dim);
return dim * apply_dimensions(std::forward<Dimensions>(dims)...);
}
size_t apply_dimensions(size_t dim) {
dimensions.emplace_back(dim);
return dim;
}
public:
Matrix(std::vector<size_t> dims) : dimensions(std::move(dims)) {
size_t size = flat_size();
_data = std::make_unique<T[]>(size);
}
template<typename ... Dimensions>
Matrix(size_t dim, Dimensions&&... dims) {
size_t size = apply_dimensions(dim, std::forward<Dimensions>(dims)...);
_data = std::make_unique<T[]>(size);
}
T & operator()(std::vector<size_t> const& indexes) {
if(indexes.size() != dimensions.size())
throw std::runtime_error("Incorrect number of parameters used to retrieve Matrix Data!");
return _data[get_flat_index(indexes)];
}
T const& operator()(std::vector<size_t> const& indexes) const {
if (indexes.size() != dimensions.size())
throw std::runtime_error("Incorrect number of parameters used to retrieve Matrix Data!");
return _data[get_flat_index(indexes)];
}
template<typename ... Indexes>
T & operator()(size_t idx, Indexes&& ... indexes) {
if (sizeof...(indexes)+1 != dimensions.size())
throw std::runtime_error("Incorrect number of parameters used to retrieve Matrix Data!");
size_t flat_index = get_flat_index(0, idx, std::forward<Indexes>(indexes)...);
return at(flat_index);
}
template<typename ... Indexes>
T const& operator()(size_t idx, Indexes&& ... indexes) const {
if (sizeof...(indexes)+1 != dimensions.size())
throw std::runtime_error("Incorrect number of parameters used to retrieve Matrix Data!");
size_t flat_index = get_flat_index(0, idx, std::forward<Indexes>(indexes)...);
return at(flat_index);
}
T & at(size_t flat_index) {
return _data[flat_index];
}
T const& at(size_t flat_index) const {
return _data[flat_index];
}
size_t dimension_size(size_t dim) const {
return dimensions[dim];
}
size_t num_of_dimensions() const {
return dimensions.size();
}
size_t flat_size() const {
size_t size = 1;
for (size_t dim : dimensions)
size *= dim;
return size;
}
private:
size_t get_flat_index(std::vector<size_t> const& indexes) const {
size_t dim = 0;
size_t flat_index = 0;
for (size_t index : indexes) {
flat_index += get_offset(index, dim++);
}
return flat_index;
}
template<typename ... Indexes>
size_t get_flat_index(size_t dim, size_t index, Indexes&& ... indexes) const {
return get_offset(index, dim) + get_flat_index(dim + 1, std::forward<Indexes>(indexes)...);
}
size_t get_flat_index(size_t dim, size_t index) const {
return get_offset(index, dim);
}
size_t get_offset(size_t index, size_t dim) const {
if (index >= dimensions[dim])
throw std::runtime_error("Index out of Bounds");
for (size_t i = dim + 1; i < dimensions.size(); i++) {
index *= dimensions[i];
}
return index;
}
};
//private:
template<typename ... Dimensions>
size_t apply_dimensions(size_t dim, Dimensions&& ... dims) {
dimensions.emplace_back(dim);
return dim * apply_dimensions(std::forward<Dimensions>(dims)...);
}
size_t apply_dimensions(size_t dim) {
dimensions.emplace_back(dim);
return dim;
}
public:
Matrix(std::vector<size_t> dims) : dimensions(std::move(dims)) {
size_t size = flat_size();
_data = std::make_unique<T[]>(size);
}
template<typename ... Dimensions>
Matrix(size_t dim, Dimensions&&... dims) {
size_t size = apply_dimensions(dim, std::forward<Dimensions>(dims)...);
_data = std::make_unique<T[]>(size);
}
int main() {
Matrix<int> mat{2, 2}; //Yields a 2x2 2D Rectangular Matrix
mat = Matrix<int>{4, 6, 5};//mat is now a 4x6x5 3D Rectangular Matrix
mat = Matrix<int>{9};//mat is now a 9-length 1D array.
mat = Matrix<int>{2, 3, 4, 5, 6, 7, 8, 9};//Why would you do this? (yet it compiles...)
}
int main() {
std::cout << "Input the sizes of each of the dimensions.\n";
std::string line;
std::getline(std::cin, line);
std::stringstream ss(line);
size_t dim;
std::vector<size_t> dimensions;
while(ss >> dim)
dimensions.emplace_back(dim);
Matrix<int> mat{dimensions};//Voila.
}
//public:
T & operator()(std::vector<size_t> const& indexes) {
if(indexes.size() != dimensions.size())
throw std::runtime_error("Incorrect number of parameters used to retrieve Matrix Data!");
return _data[get_flat_index(indexes)];
}
T const& operator()(std::vector<size_t> const& indexes) const {
if (indexes.size() != dimensions.size())
throw std::runtime_error("Incorrect number of parameters used to retrieve Matrix Data!");
return _data[get_flat_index(indexes)];
}
template<typename ... Indexes>
T & operator()(size_t idx, Indexes&& ... indexes) {
if (sizeof...(indexes)+1 != dimensions.size())
throw std::runtime_error("Incorrect number of parameters used to retrieve Matrix Data!");
size_t flat_index = get_flat_index(0, idx, std::forward<Indexes>(indexes)...);
return at(flat_index);
}
template<typename ... Indexes>
T const& operator()(size_t idx, Indexes&& ... indexes) const {
if (sizeof...(indexes)+1 != dimensions.size())
throw std::runtime_error("Incorrect number of parameters used to retrieve Matrix Data!");
size_t flat_index = get_flat_index(0, idx, std::forward<Indexes>(indexes)...);
return at(flat_index);
}
Matrix<int> mat{6, 5};
mat(5, 2) = 17;
//mat(5, 1, 7) = 24; //throws exception at runtime because of wrong number of dimensions.
mat = Matrix<int>{9, 2, 8};
mat(5, 1, 7) = 24;
//mat(5, 2) = 17; //throws exception at runtime because of wrong number of dimensions.
std::vector<size_t> indexes;
/*...*/
mat(indexes) = 54; //Will throw if index count is wrong, will succeed otherwise