Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Expand std::tuple to use as initialiser for class

Tags:

c++

c++11

tuples

I want to use all elements of a std::tuple as an initialiser for a class. Is there a simpler way than doing std::get<i-th element>(std::tuple) for each element of the tuple?

Minimum working example with 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" );
}

See http://coliru.stacked-crooked.com/a/4a5d45dbf1461407 for Live example

like image 776
meddle0106 Avatar asked Apr 08 '16 08:04

meddle0106


People also ask

How to use tuples in C++?

Tuples in C++. 1. get() :- get() is used to access the tuple values and modify them, it accepts the index and tuple name as arguments to access a particular tuple element. 2. make_tuple() :- make_tuple() is used to assign tuple with values. The values passed should be in order with the values declared in tuple.

How to expand/unpack tuple in C++?

In C++ there is many ways of expanding/unpacking tuple and apply those tuple elements to a variadic template function. Here is a small helper class which creates index array. It is used a lot in template metaprogramming:

Is_move_constructible for an empty tuple in C++?

For the empty tuple std::tuple<>, it is constexpr . std::is_move_constructible<Ti>::value must be true for all i, otherwise the behavior is undefined (until C++20)this overload does not participate in overload resolution (since C++20).

What is a tuple in Python?

A tuple is an object that can hold a number of elements. The elements can be of different data types. The elements of tuples are initialized as arguments in order in which they will be accessed.


2 Answers

As Kerrek SB commented there's already a proposal for this P0209R0. Consequently, until it's in the standard you could do something along these lines:

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());
}

And initialize your class as:

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

Live Demo

You could also hand-craft index_sequence and make_index_sequence for this to work in C++11 as proposed by Jarod42 here, and change to:

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());
}

Live Demo

like image 55
101010 Avatar answered Sep 19 '22 02:09

101010


I don't think there is anything standard that might help you.

However you can do it in following way:

Do c-tor in A?

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)){}
};

Alternatively you can do factory like function:

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

Code is untested and might have syntax errors.

like image 28
Nick Avatar answered Sep 20 '22 02:09

Nick