将std::tuple扩展为类的初始化器

10

我想使用一个 std::tuple 中的所有元素作为一个类的初始化器。是否有比对元组中的每个元素执行std::get<i-th element>(std::tuple)更简单的方法?

带有std::get的最小可行示例:

#include <string>
#include <tuple>
#include <cassert>

struct A
{
    std::string string1;
    int intVal;
    std::string string2;
};

int main()
{
  std::tuple< std::string, int, std::string > myTuple("S1", 42, "S2");

  A myA{ std::get<0>(myTuple), std::get<1>(myTuple), std::get<2>(myTuple) };

  assert( myA.string1 == "S1" );
  assert( myA.intVal  == 42   );
  assert( myA.string2 == "S2" );
}

请查看http://coliru.stacked-crooked.com/a/4a5d45dbf1461407,获取实时示例。


6
好的,请告诉我需要翻译的内容。 - Kerrek SB
2个回答

5

正如Kerrek SB在评论中提到的,已经有一个关于此问题的提案:P0209R0。因此,在该提案被纳入标准之前,您可以按以下方法操作:

template<typename C, typename T, std::size_t... I>
decltype(auto) make_from_tuple_impl(T &&t, std::index_sequence<I...>) {
  return C{std::get<I>(std::forward<T>(t))...};
}

template<typename C, typename... Args, typename Indices = std::make_index_sequence<sizeof...(Args)>>
decltype(auto) make_from_tuple(std::tuple<Args...> const &t) {
  return make_from_tuple_impl<C>(t, Indices());
}

并将您的类初始化为:

A myA{make_from_tuple<A>(myTuple)};

演示实例

你也可以手动创建index_sequencemake_index_sequence,使其在C++11中起作用,就像Jarod42这里提出的那样,并将代码更改为:

namespace idx {
  template <std::size_t...> struct index_sequence {};

  template <std::size_t N, std::size_t... Is>
  struct make_index_sequence : make_index_sequence<N - 1, N - 1, Is...> {};

  template <std::size_t... Is>
  struct make_index_sequence<0u, Is...> : index_sequence<Is...> { using type = index_sequence<Is...>; };
}

template<typename C, typename T, std::size_t... I>
C make_from_tuple_impl(T &&t, idx::index_sequence<I...>) {
  return C{std::get<I>(std::forward<T>(t))...};
}

template<typename C, typename... Args, typename Indices = idx::make_index_sequence<sizeof...(Args)>>
C make_from_tuple(std::tuple<Args...> const &t) {
  return make_from_tuple_impl<C>(t, Indices());
}

实时演示


解决方案很好。不幸的是,这个解决方案需要 C++14,而我目前无法使用它。我回溯了 backport index_sequence 和 make_index_sequence,所以我仍然可以使用它。很好。 - meddle0106
@meddle0106 我会尝试给出一个C++11版本。 - 101010

1
我认为没有任何标准能够帮助你。
但是你可以按照以下方式操作:
在 A 中执行 c-tor?
struct A
{
    std::string string1;
    int intVal;
    std::string string2;

    template<class T>
    A(const T &t) :
               string1(std::get<0>(t), 
               intVal(std::get<1>(t)), 
               string2(std::get<2>(t)){}
};

另外,您可以使用类似工厂的函数:
    template<class T>
    A createA(const T &t){
        return A { 
               std::get<0>(t), 
               std::get<1>(t), 
               std::get<2>(t)
        };
    }

代码未经测试,可能存在语法错误。


因为您有字符串,所以您可能需要编写更多的代码来处理通用引用,并使用 std::move / std::forward 来传递字符串。 - Nick

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