The question is pretty straight, how could I generate :
std::tuple<float, int, double>
If I know the type :
struct Foo { float a; int b; double c; };
And how could I retrieve the data, in both convertion?
The question is pretty straight, how could I generate :
std::tuple<float, int, double>
If I know the type :
struct Foo { float a; int b; double c; };
And how could I retrieve the data, in both convertion?
You cannot do this in C++, as it would require a language feature known as reflection.
Instead, "manually" build the tuple or just begin with a tuple in the first place.
Alternatively, you could build a script in Python (or similar) to preprocess your code and auto-generate the resulting conversion.
You can write a conversion operator.
struct Test {
int a;
float b;
double c;
explicit operator std::tuple<int, float, double>() const {
return {a, b, c};
}
};
Then, use it like that:
int main() {
Test t{12, 3.2f, 4.5};
std::tuple tt = t;
}
As other answer said, there is no way to do this in a generic way in C++14.
However, there is a trick in C++17 that uses structured bindings:
template<typename T>
auto as_tuple_ref( T & t )
{
auto &[a,b,c] = t;
return std::tie(a,b,c);
}
struct Foo { float a; int b; double c; };
Foo bar;
int & b_ref = std::get<1>( as_tuple_ref(bar) );
This version only works for structures with 3 members, but I believe that with some time and effort (and some SFINAE) it is possible to write a fully generic solution (and it will probably involve a lot of copy-paste).
You can do it manually. For example:
#include <iostream>
#include <tuple>
using std::tuple;
using std::cout;
using std::endl;
using std::get;
struct Foo { float a; int b; double c; };
int main()
{
auto tuple_foo = tuple<decltype(Foo::a), decltype(Foo::b), decltype(Foo::c)>{1.1f, 10, 100.001};
cout << "<0>: " << get<0>(tuple_foo) << endl;
cout << "<1>: " << get<1>(tuple_foo) << endl;
cout << "<2>: " << get<2>(tuple_foo) << endl;
}
Based on those member names, i.e.: the 1st member is called a
, the 2nd b
, and the 3rd c
. You can define the following struct template, member_type<>
, to pick up the type of each individual member:
template<typename T>
struct member_type : T {
using a_t = decltype(T::a);
using b_t = decltype(T::b);
using c_t = decltype(T::c);
};
With this alias template, tuple_splitter<>
, you can define a tuple from a struct
with such members (named a
, b
and c
):
template<typename T>
using tuple_splitter = std::tuple
<
typename member_type<T>::a_t,
typename member_type<T>::b_t,
typename member_type<T>::c_t
>;
Then, for your Foo
:
tuple_splitter<Foo> foo_tuple;
foo_tuple
will have the type std::tuple<float, int, double>
.
If you define now a new struct
, Bar
, as:
struct Bar { int a; char b; float c; };
Then:
tuple_splitter<Bar> bar_tuple;
bar_tuple
will be of type std::tuple<int, char, float>
.
Using std::tie even makes it easier:
struct foo
{
int value1;
int value2;
string str;
};
void main()
{
std::tuple<int, int, string> a{ 1, 1, "Hello " };
foo b;
std::tie(b.value1, b.value2, b.str) = a;
}