模板化向量的向量

6
我想创建一个向量的向量,其中单个向量可以是不同类型,具体操作如下:
std::vector<int> v1;
std::vector<float> v2;
std::vector<double> v3;

std::vector<SomeType> all;
all.push_back(v1);
all.push_back(v2);
all.push_back(v3);

在这种情况下,SomeType 应该是什么?

我的实际应用场景:

我有不同数据类型的向量,需要将它们写入磁盘。每次添加一个列到数据集时,我不想在各个不同的地方指定该列。我希望可以轻松地遍历列。


9
std::variant是一个C++标准库中的容器类,它可以存储多种类型的值,但每次只能存储其中一种类型。使用std::variant可以避免手动维护多个不同类型的变量或指针。关于您所需要解决的真正问题,我很好奇。您认为为什么需要这样一个向量? - Some programmer dude
1
你如何知道从 all[1] 返回到 std::vector<float> - Botje
5
克制一下。这不是语言的正常构造方式。我的建议是寻找另一种设计,允许更符合惯用法的C++代码。虽然这样做肯定是可能的,但使用和维护会很困难。 - Serge Ballesta
“向数据集添加一列”是在编译时还是运行时发生的?听起来你正在描述 struct Row { int a; float x; double price; }; std::vector<Row> all; - Caleth
是的,那就是我所拥有的。但在写出这些值时,我有单独的向量需要取出结构体的各个值。理想情况下,我可以迭代结构体成员。 - user3055163
我建议将你想要解决的实际问题作为一个单独的问题发布。可能有其他更优雅的解决方案,不涉及不同类型的向量。 - rinspy
2个回答

5

根据您的情况,有很多方法可以实现这个目标。以下是一种使用std::variant的变体(双关语):

std::vector<int> v1 = { 1, 2, 3 };
std::vector<float> v2 = { 4.5f, 5.5f, 6.5f };
std::vector<double> v3 = { 7.5, 8.5, 9.5 };

std::vector<std::variant<std::vector<int>, std::vector<float>, std::vector<double>>> all;
all.push_back(v1);
all.push_back(v2);
all.push_back(v3);

for(auto& variant : all)
{
    std::visit([](const auto& container) {
        for(auto value : container)
        {
            std::cout << value << '\n';
        }
    }, variant);
}

std::any 使用类型擦除也可以工作。或者再往下一层,例如使用 std::vector<std::variant<int, float, double>>


有没有一种方法可以在不手动指定“all”容器类型的情况下完成这个操作? - user3055163
你可以使用typedef来定义内部变量:using MyVariant = std::variant< ... >;,并在类型可以被推断的情况下使用auto。但是你至少要声明一次 :) - One Man Monkey Squad

0

你不能这样做,因为所有三种向量类型都不同。

但是,你可以创建一个非模板的抽象类,其中包含你需要用于std::vector的所需抽象函数,然后为每种向量类型实现它。

像这样:

struct Base
{
      int size() = 0;
};

template <typename T>
struct VectorWrapper : public Base
{
      std::vector<T>* mVector;
      int size() { return mVector.size(); }
};

int main()
{
     std::vector<int> v;
     // initialize vector

     VectorWrapper<int> w;
     w.mVector = &v;

     std::vector<Base*> all;
     all.push_back(&w)

     return 0; 
}

但是如果我想遍历整个向量,我该如何访问底层的mVector而不必转换为VectorWrapper?如果这种情况下我需要知道类型,那么我就不能循环遍历它了吗? - user3055163
是的,你必须进行类型转换。但是当类型不匹配时,dynamic_cast会返回nullptr,因此如果你只期望几种类型,你可以使用动态转换来处理每种情况,并检查你没有得到nullptr。但到那时,最好找到一种方法来避免使用这个向量的向量。 - Henry
@user3055163 这就是为什么整个概念基本上是有缺陷的。如果您知道类型,那么只能循环遍历某些内容,并且一旦创建了 std::vector<SomeType>,就没有简单的方法来获取该类型。std::variantstd::visit 可能会对您有所帮助,或者使用其他形式的严格模板(如果您具有从列索引到类型的编译时映射)。 - Max Langhof

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接