【问题标题】:Vector of templated vectors模板化向量的向量
【发布时间】:2019-10-22 17:23:50
【问题描述】:

我想创建一个向量的向量,其中各个向量可以是不同的类型,如下所示:

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 在这种情况下应该是什么?

我的实际用例:

我有不同数据类型的向量需要写入磁盘。每次我向数据集添加一列时,我都不想在不同的地方指定该列。我希望能够轻松地遍历列。

【问题讨论】:

  • std::variant?但我真的很好奇你需要解决的真正的问题? 为什么你认为你需要这样一个向量?
  • 你怎么知道从all[1]回到std::vector&lt;float&gt;
  • 不要。这不是语言从头开始构建的方式。我的建议是找到一个允许更多惯用 C++ 代码的不同设计。这当然是可能的,但很难使用和维护。
  • “向数据集添加列”是在编译时发生还是在运行时发生?听起来你在描述struct Row { int a; float x; double price; }; std::vector&lt;Row&gt; all;
  • 是的,这就是我所拥有的。但是在写出这些值时,我有单独的向量需要获取结构的各个值。理想情况下,我可以遍历结构成员。

标签: c++ templates vector


【解决方案1】:

您不能这样做,因为所有 3 种矢量类型都不同。

但是,您可以使用 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; 
}

【讨论】:

  • 但是,如果我想遍历所有向量,如何在不强制转换为 VectorWrapper 的情况下访问底层 mVector?在这种情况下,我需要知道类型,这意味着我不能循环遍历它?
  • 是的,你必须投。当类型不匹配时,dynamic_cast 返回 nullptr,因此,如果您期望的类型只有少数,您可以使用动态转换来处理每种情况,并检查您没有返回 nullptr。但到那时,可能值得找到一种方法来做你正在做的事情,而无需这个向量向量
  • @user3055163 这就是为什么整个概念存在很大缺陷的原因。如果您知道类型,则只能循环访问某些内容,并且在创建 std::vector&lt;SomeType&gt; 后没有简单的方法可以获取该类型。 std::variantstd::visit 可能会对您有所帮助,或者其他形式的严格模板(如果您有从列索引到类型的编译时映射)。
【解决方案2】:

有很多方法可以做到这一点,具体取决于您的情况。这是一个带有 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 类型擦除也可以。或者再低一级,f.i. std::vector&lt;std::variant&lt;int, float, double&gt;&gt;

【讨论】:

  • 有没有办法在不手动指定all的容器类型的情况下做到这一点?
  • 您可以 typedef 内部变体:使用 MyVariant = std::variant;,并在可以推断类型的地方使用 auto。但是你必须至少声明一次:)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-10-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-08-03
相关资源
最近更新 更多