如何创建可调整大小和固定大小容器的变体
How to create a variant of re-sizeable and fixed size containers
我有一个 class,其基础数据是 std::vector
、std::unique_ptr
和 std::deque
的变体。这显示在下面的代码中。
template<class T>
class matrix2d
{
private:
typename std::variant<std::vector<T>,
std::unique_ptr<T[]>,
std::deque<T>> data;
public:
matrix2d<T>() = delete;
matrix2d<T>(size_t h, size_t w, int type) {
try {
switch (type) {
case 0:
data = std::vector<T>(h*w);
break;
case 1:
data = std::make_unique<T[]>(h*w);
break;
case 2:
data = std::deque<T>(h*w);
break;
default:
throw std::runtime_error("Unrecognized type of matrix2d class data");
}
}
catch (const std::exception& e) {
std::cerr << e.what() << std::endl;
}
}
auto operator[](size_t i) {
return (std::begin(data) + i);
}
};
int main()
{
matrix2d<int> a2d(4,5,0);
for (size_t i{}; i<4; ++i) {
for (size_t j{}; j<5; ++j) {
a2d[i][j] = 5.0;
}
}
}
我的问题如下:
可以创建 unique_ptr
和其他可调整大小容器的联合吗?
另外,如何重载下标运算符 [] 使 class 函数成为二维数组?
变体有效。
然而,访问行的用法需要对 std::vector<T>
和 std::unique_ptr<T[]>
一方面 和 std::deque<T>
[=64= 进行不同的处理]另一方面。由于 vector
和 unique_ptr<T[]>
使用连续内存,因此 deque
的元素不需要连续存储。
假设我们首先要为向量实现 operator[] 和 unique_ptr.
步骤 1
我们需要向 class 添加一个成员来保存行的大小,这是计算第 i 行在数组中的位置所必需的。
那么假设您添加了一个私有成员 'w':
size_t w;
并且您在构造函数中对其进行了初始化:
matrix2d<T>(size_t h, size_t w, int type) : w(w) {
// ...
第 2 步
现在我们要找的运算符[]可以是这样的:
auto operator[](size_t i) {
return std::visit([i, w = this->w](auto&& arg){return &arg[i*w];}, data);
}
即使我们在这里对 std::variant
管理的任何类型使用相同的操作,也需要使用 std::visit
。但是,std::visit
也可以对每种存储类型进行不同的操作,请参阅 std::visit on cppreference。
步骤 3
如果我们也想支持deque
,这需要不同的处理方式。
目前我们的运营商[] returns T* 我们想保留它。
对于双端队列,我们不能只获取一行中第一个元素的地址,并假设同一行中的所有元素都紧接着连续地相邻存储。因此,为了允许以相同的方式使用双端队列,我们至少需要行是连续的。我们可以用 Ts 向量的双端队列来实现。在 class 中的 variant
声明中可能看起来像这样:
std::variant< std::vector<T>,
std::unique_ptr<T[]>,
td::deque<std::vector<T>> > data;
在构造函数中,deque
的初始化为:
case 2: { // TODO: use enum instead
auto d = std::deque<std::vector<T>>(h);
for(auto& item : d) {
item = std::vector<T>(w);
}
data = d;
}
break;
operator[] 现在将更改为:
auto operator[](size_t i) {
return std::visit([i, w = this->w](auto&& arg){
using U = std::decay_t<decltype(arg)>;
if constexpr (std::is_same_v<U, std::deque<std::vector<T>>>) {
return &arg[i][0];
}
else {
return &arg[i*w];
}
}, data);
}
我有一个 class,其基础数据是 std::vector
、std::unique_ptr
和 std::deque
的变体。这显示在下面的代码中。
template<class T>
class matrix2d
{
private:
typename std::variant<std::vector<T>,
std::unique_ptr<T[]>,
std::deque<T>> data;
public:
matrix2d<T>() = delete;
matrix2d<T>(size_t h, size_t w, int type) {
try {
switch (type) {
case 0:
data = std::vector<T>(h*w);
break;
case 1:
data = std::make_unique<T[]>(h*w);
break;
case 2:
data = std::deque<T>(h*w);
break;
default:
throw std::runtime_error("Unrecognized type of matrix2d class data");
}
}
catch (const std::exception& e) {
std::cerr << e.what() << std::endl;
}
}
auto operator[](size_t i) {
return (std::begin(data) + i);
}
};
int main()
{
matrix2d<int> a2d(4,5,0);
for (size_t i{}; i<4; ++i) {
for (size_t j{}; j<5; ++j) {
a2d[i][j] = 5.0;
}
}
}
我的问题如下:
可以创建 unique_ptr
和其他可调整大小容器的联合吗?
另外,如何重载下标运算符 [] 使 class 函数成为二维数组?
变体有效。
然而,访问行的用法需要对 std::vector<T>
和 std::unique_ptr<T[]>
一方面 和 std::deque<T>
[=64= 进行不同的处理]另一方面。由于 vector
和 unique_ptr<T[]>
使用连续内存,因此 deque
的元素不需要连续存储。
假设我们首先要为向量实现 operator[] 和 unique_ptr.
步骤 1
我们需要向 class 添加一个成员来保存行的大小,这是计算第 i 行在数组中的位置所必需的。
那么假设您添加了一个私有成员 'w':
size_t w;
并且您在构造函数中对其进行了初始化:
matrix2d<T>(size_t h, size_t w, int type) : w(w) {
// ...
第 2 步
现在我们要找的运算符[]可以是这样的:
auto operator[](size_t i) {
return std::visit([i, w = this->w](auto&& arg){return &arg[i*w];}, data);
}
即使我们在这里对 std::variant
管理的任何类型使用相同的操作,也需要使用 std::visit
。但是,std::visit
也可以对每种存储类型进行不同的操作,请参阅 std::visit on cppreference。
步骤 3
如果我们也想支持deque
,这需要不同的处理方式。
目前我们的运营商[] returns T* 我们想保留它。
对于双端队列,我们不能只获取一行中第一个元素的地址,并假设同一行中的所有元素都紧接着连续地相邻存储。因此,为了允许以相同的方式使用双端队列,我们至少需要行是连续的。我们可以用 Ts 向量的双端队列来实现。在 class 中的 variant
声明中可能看起来像这样:
std::variant< std::vector<T>,
std::unique_ptr<T[]>,
td::deque<std::vector<T>> > data;
在构造函数中,deque
的初始化为:
case 2: { // TODO: use enum instead
auto d = std::deque<std::vector<T>>(h);
for(auto& item : d) {
item = std::vector<T>(w);
}
data = d;
}
break;
operator[] 现在将更改为:
auto operator[](size_t i) {
return std::visit([i, w = this->w](auto&& arg){
using U = std::decay_t<decltype(arg)>;
if constexpr (std::is_same_v<U, std::deque<std::vector<T>>>) {
return &arg[i][0];
}
else {
return &arg[i*w];
}
}, data);
}