Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/128.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 如何创建可重新调整大小和固定大小容器的变体_C++_Stl_C++17_Unions_Variant - Fatal编程技术网

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

C++ 如何创建可重新调整大小和固定大小容器的变体,c++,stl,c++17,unions,variant,C++,Stl,C++17,Unions,Variant,我有一个类,它的底层数据是std::vector、std::unique\u ptr和std::deque的变体。这在下面的代码中显示 template<class T> class matrix2d { private: typename std::variant<std::vector<T>, std::unique_ptr<T[]>, s

我有一个类,它的底层数据是
std::vector
std::unique\u 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;
        }
    }
}
模板
类矩阵2d
{
私人:
typename std::变量数据;
公众:
matrix2d()=删除;
矩阵2d(大小h、大小w、整数类型){
试一试{
开关(类型){
案例0:
数据=标准::向量(h*w);
打破
案例1:
数据=标准::使_唯一(h*w);
打破
案例2:
数据=std::deque(h*w);
打破
违约:
抛出std::runtime_错误(“无法识别的matrix2d类数据类型”);
}
}
捕获(const std::exception&e){
std::cerr该变体有效

然而,访问行的用法一方面需要对
std::vector
std::unique_ptr
进行不同的处理,另一方面需要对
std::deque
进行不同的处理。由于
vector
unique_ptr
使用连续内存,因此
deque
的元素不需要连续存储

假设我们首先只为向量和唯一的ptr实现运算符[]

第一步 我们需要向类中添加一个成员,该成员将保持行的大小,这是计算行号i数组中的位置所必需的

假设您添加了一个私有成员“w”:

size_t w;
并在构造函数中初始化它:

matrix2d<T>(size_t h, size_t w, int type) : w(w) {
   // ...
即使我们在这里对我们的
std::variant
管理的任何类型使用相同的操作,也需要使用
std::visit
。但是,
std::visit
也可以对存储的每种类型执行不同的操作,请参阅

步骤3 如果我们想同时支持
deque
,这需要不同的处理方法

目前,我们的运算符[]返回T*,我们希望保留它

对于deque,我们不能只获取一行中第一个元素的地址,并假设同一行中的所有元素都紧接着连续存储。因此,为了允许使用相同的方法使用deque,我们至少需要行是连续的。我们可以通过Ts向量的deque来实现这一点。在<代码>变量
类中的声明:

 std::variant< std::vector<T>,
               std::unique_ptr<T[]>,
               td::deque<std::vector<T>> > data;
操作员[]现在将更改为:

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);
}
auto操作符[](大小i){
return std::visit([i,w=this->w](自动和参数化){
使用U=std::decation\U t;
如果constexpr(std::is_same_v){
返回参数[i][0];
}
否则{
返回参数&arg[i*w];
}
},数据);
}


每个问题一个问题。对于构造函数没有区别。等效。首选枚举(类)为了可读性,使用简单的int表示类型。在运行时选择容器类型有什么意义?您需要为每次访问支付运行时开销…:@Jarod42同意。但关键是在任何给定时间都可以选择我想要的容器。至于运行时开销,这就是为什么我想知道是否有更好的分配方法容器的空间。也许,使用std::visit?请注意,行上的循环偏移了1。在回答中,我注意到所包含标题的顺序发生了变化。重新排序有特殊原因吗?没有。我没有看到您的包含。
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;
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);
}