如何创建可调整大小和固定大小容器的变体

Posted

技术标签:

【中文标题】如何创建可调整大小和固定大小容器的变体【英文标题】:How to create a variant of re-sizeable and fixed size containers 【发布时间】:2019-12-14 18:23:59 【问题描述】:

我有一个类,其基础数据是std::vectorstd::unique_ptrstd::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&lt;T&gt;std::unique_ptr&lt;T[]&gt;std::deque&lt;T&gt;进行不同的处理。由于vectorunique_ptr&lt;T[]&gt; 使用连续内存,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 容器?

如何使 iframe 可调整大小?

可调整大小的 PyQt 小部件显示具有固定纵横比的图像

如何在 Pyqt 中创建可调整大小的布局 UI?

如何在使用 jQuery(可拖动和可调整大小)拖动光标时调整图像大小

如何使用 jQuery UI 获取可拖动和可调整大小元素的坐标