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
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.
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:
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).
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.
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
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With