1

我将如何制作一个std::vector包含 a 中包含的所有类型的默认构造实例的 a std::variant

using TaskVariant = std::variant<TypeA, TypeB, TypeC>;
std::vector<TaskVariant> variants;

// I'd like to do this in a loop
variants.push_back(TypeA());
variants.push_back(TypeB());
variants.push_back(TypeC());
4

4 回答 4

6

1.解决方案:您可以将变量转换为元组,然后使用 C++17 std::apply

#include <variant>
#include <iostream>
#include <string>
#include <vector>
#include <tuple>

using namespace std;

template <typename... Types>
struct ToTuple;

template <typename... Types>
struct ToTuple<variant<Types...>>
{
    using type = tuple<Types...>;
};

struct TypeA {};
struct TypeB {};
struct TypeC {};

using TaskVariant = std::variant<TypeA, TypeB, TypeC>;

int main()
{
    vector<TaskVariant> vec;
    apply([&vec](auto&&... args) {(vec.push_back(args), ...); }, ToTuple<TaskVariant>::type{});
}

编辑:

2.解决方案:使用make_index_sequencevariant_alternative_tvariant_size_v(所有 C++17)(感谢@sd指出variant_alternative_t,但我已经修改了使用make_index_sequence而不是递归的示例):

#include <variant>
#include <iostream>
#include <string>
#include <vector>
using namespace std;

struct TypeA {};
struct TypeB {};
struct TypeC {};

using TaskVariant = std::variant<TypeA, TypeB, TypeC>;

template <size_t... Idx>
void fill_vec(vector<TaskVariant>& vec, index_sequence<Idx...> idx)
{
    (vec.push_back(variant_alternative_t<Idx, TaskVariant>{}), ...);
}

int main()
{
    vector<TaskVariant> vec;
    fill_vec(vec, make_index_sequence<variant_size_v<TaskVariant>>{});
}
于 2020-09-10T06:35:16.180 回答
4

另一个解决方案

#include <iostream>
#include <variant>
#include <vector>

struct TypeA {
  int a;
  TypeA() : a{0} {std::cout<<"A"<<std::endl;};
};

struct TypeB {
  int b;
  TypeB() : b{0} {std::cout<<"B"<<std::endl;};
};

struct TypeC {
  int c;
  TypeC() : c{0} {std::cout<<"C"<<std::endl;};
};

using TaskVariant = std::variant<TypeA, TypeB, TypeC>;

template<class var, std::size_t I = 0>
void autofill(std::vector<var>& vec){
  if constexpr(I < std::variant_size_v<var>){
    vec.push_back(std::variant_alternative_t<I, var>{});
    autofill<var, I + 1>(vec);
  }
}


int main() {
  std::vector<TaskVariant> variants;

  autofill(variants);
}

编辑:完全忘记了 C++17 中的这个特性。

template<class... VA> //VA for variant alternatives
void autofill(std::vector<std::variant<VA...> >& vec) {
    (..., vec.emplace_back(VA{}));
}

https://en.cppreference.com/w/cpp/language/fold 编辑 2:似乎@max 在大约 4 小时前击败了我 ^^

于 2020-09-10T09:46:21.150 回答
3

在类型上使用模板折叠(逗号运算符)怎么样?

#include <variant>
#include <vector>

struct TypeA {};
struct TypeB {};
struct TypeC {};

using TaskVariant = std::variant<TypeA, TypeB, TypeC>;

template <typename ... Ts>
void addTypes (std::vector<std::variant<Ts...>> & vec)
 { (vec.push_back(Ts{}), ...); }

int main()
 {
   std::vector<TaskVariant> vec;

   addTypes(vec);
 }
于 2020-09-10T15:04:12.790 回答
1

这里使用可变参数模板的示例解决方案。

#include <vector>
#include <variant>
#include <iostream>
#include <typeinfo>

struct TypeA {};
struct TypeB {};
struct TypeC {};

using TaskVariant = std::variant<TypeA, TypeB, TypeC>;

template <class T>
void addValue(std::vector<TaskVariant> & v)
{
 v.push_back(T());
 std::cout << "adding " << typeid(T).name() << " default ctor\n";
}

template <class T, class V, class... Args>
void addValue(std::vector<TaskVariant> & v)
{
  addValue<T>(v);
  addValue<V, Args...>(v);
}

template <class... Args>
void addValues(std::vector<std::variant<Args...>> & v)
{
  addValue<Args...>(v);
}

int main()
{
  std::vector<TaskVariant> variants;
  addValues(variants);
}

输出是:

adding 5TypeA default ctor
adding 5TypeB default ctor
adding 5TypeC default ctor
于 2020-09-10T06:29:44.070 回答