如何创建可调整大小和固定大小容器的变体
Posted
技术标签:
【中文标题】如何创建可调整大小和固定大小容器的变体【英文标题】:How to create a variant of re-sizeable and fixed size containers 【发布时间】:2019-12-14 18:23:59 【问题描述】:我有一个类,其基础数据是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
和其他可调整大小的容器的联合?
另外,如何重载下标运算符 [] 以使类函数成为二维数组?
【问题讨论】:
每个问题一个问题。对于构造函数来说没有区别。等价的。 为了便于阅读,优先使用枚举(类)而不是简单的 int。 在运行时选择容器类型有什么意义?此外,您还要为每次访问支付运行时开销......: @Jarod42 同意。但关键是可以在任何给定时间选择我想要的任何容器。至于运行时开销,这就是为什么我想知道是否有更好的方法来为容器分配空间。也许,使用 std::visit? 请注意,行上的循环偏移了一个 【参考方案1】:变体有效。
然而,访问行的用法需要对std::vector<T>
和std::unique_ptr<T[]>
和std::deque<T>
进行不同的处理。由于vector
和unique_ptr<T[]>
使用连续内存,deque
的元素不需要连续存储。
假设我们首先要为 vector 和 unique_ptr 实现 operator[]。
步骤 1
我们需要在类中添加一个成员来保存行的大小,这是计算行号 i 在数组中的位置所必需的。
假设您添加了一个私有成员“w”:
size_t w;
并且你在构造函数中初始化它:
matrix2d<T>(size_t h, size_t w, int type) : w(w)
// ...
第二步
现在我们正在寻找的 operator[] 可以如下所示:
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。
第三步
如果我们也想支持deque
,这需要不同的处理方式。
目前我们的 operator[] 返回 T*,我们想保留它。
对于双端队列,我们不能只取一行中第一个元素的地址,并假设同一行中的所有元素都紧随其后,连续地存储。因此,为了允许使用相同的方法使用双端队列,我们至少需要行是连续的。我们可以通过 Ts 的向量双端队列来实现。这在类中的 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);
http://coliru.stacked-crooked.com/a/192fbf6705aecc7c
【讨论】:
在答案中,我注意到包含的标题的顺序发生了变化。重新订购是否有特殊原因? 没有。我还没有看到你的包含。以上是关于如何创建可调整大小和固定大小容器的变体的主要内容,如果未能解决你的问题,请参考以下文章
如何创建带有导航抽屉和可调整大小内容的 Vuetify 容器?