如何使用可变参数模板定义不同类型的向量的向量?

时间:2018-10-08 15:22:55

标签: c++ templates vector c++17

我想制作一个包含不同类型向量的向量。假设我有4节课;狗,猫,猪,牛我想要一个包含每个向量的向量,并且能够通过两个索引访问它们,以便我可以对它们进行迭代,如果它是向量的向量就是这种情况。

我一直在玩类似的东西:

std::vector<std::variant<std::vector<Dog>,
    std::vector<Cat>,
    std::vector<Pig>,
    std::vector<Cow>>>;

此外,我希望能够使用可变参数模板构造来构建这些数组,因此我可以轻松地制作另一个向量载体,例如Apple,Pear,Orange,Lemon,Lemon,Grape,Cherry。

我希望能够在我的代码中写一些东西:

MyVectorOfVectors<Dog,Cat,Pig,Cow> animals;
MyVectorOfVectors<Apple, Pear, Orange, Lemon, Grape, Cherry> fruits;

并为每种类型制作向量,并将这些向量存储在我可以通过索引访问的另一个向量(或类似向量)中。显然,该载体将需要是上述变体载体所建议的某种异构容器。我想这将必须包装在某种可变参数模板类定义中。

因此访问数组中的第三个Dog将需要类似这样的功能

Dog mydog = animals[0][3];

或者如果解决方案必须包装在一个类中,

Dog mydog = animals.thearray[0][3];

我意识到这可以使用类层次结构,动态分配和指向对象的指针来实现,但是我正在寻找一种具有平面内存模型的解决方案以提高性能。

4 个答案:

答案 0 :(得分:3)

template<typename... T>
using MyVectorOfVectors = std::tuple<std::vector<T>...>;

MyVectorOfVectors<Dog,Cat,Pig,Cow> animals;
MyVectorOfVectors<Apple, Pear, Orange, Lemon, Grape, Cherry> fruits;

void foo()
{
    std::vector<Dog>& dogs = std::get<0>(animals);
    std::vector<Orange>& oranges = std::get<2>(fruits);
}

Demo

您必须决定:要么可以在编译时推断类型(在这种情况下,还必须在编译时知道您对MyVectorOfVectors的索引)-然后,您将获得所有类型安全性(如上所述)。

如果索引也可以是运行时值,则需要一种类型的擦除类型。这将带有您要避免的运行时开销。

无论如何,您都不会得到Dog dog = animals[0][3],因为无论operator[]最终是什么,MyVectorOfVectors的参数在编译时不一定是已知的(从至少是编译器)。

答案 1 :(得分:1)

感谢您的建议。我使用Max Langhof的答案来生成数据结构,并找出了进行迭代的方法。

这是我最后得到的代码。

$("a[href='#button1']").click(function(e) {
    $($(this).attr("href")).click();
});

如您所见,它与使用类型推断的非层次类一起使用,因此不需要我的Dog,Cat等从基类派生。

下一步是能够在lambda中使用参数,但至少我已经了解了这一点。

答案 2 :(得分:0)

我不确定这是您所需要的,对我来说这是一个奇怪的要求:

template<typename ...Ts>
using MatrixVariantRows = std::vector<std::variant<std::vector<Ts>...>>;

https://wandbox.org/permlink/Jl9j29TgyaXKZAvh

答案 3 :(得分:0)

根据您的要求,这是另一种可能性。需要权衡的是,从编译器的角度来看,您可以混合动物或水果(但不能混合动物和水果),但是该变体可确保在运行时无法访问错误的类型。

struct Dog {};
struct Cat {};
struct Pig {};
struct Cow {};
struct Apple {};
struct Pear {};
struct Orange {};
struct Lemon {};
struct Grape {};
struct Cherry {};

template<typename... Ts>
using MetaVector = std::vector<std::vector<std::variant<Ts...>>>;

int main(int argc, const char *argv[])
{
    Dog daisy, sadie, molly;
    Cat sam, coco, tiger;
    Pig frankie, albert, digger;

    MetaVector<Dog,Cat,Pig,Cow> animals = {{ daisy, sadie, molly },
                                           { sam, coco, tiger },
                                           { frankie, albert, digger }};
    auto dog0 = std::get<Dog>(animals[0][0]);
    auto dog1 = std::get<Dog>(animals[0][1]);
    auto dog2 = std::get<Dog>(animals[0][2]);

    auto cat0 = std::get<Cat>(animals[0][0]); // throws exception

    MetaVector<Apple,Pear,Orange,Lemon,Grape,Cherry> fruits;

    return 0;
}
相关问题