将结构拆分为元组
Split a struct into a tuple
问题很直接,我怎么生成:
std::tuple<float, int, double>
如果我知道类型:
struct Foo { float a; int b; double c; };
我如何在这两种转换中检索数据?
您可以手动完成。例如:
#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;
}
您不能在 C++ 中执行此操作,因为它需要一种称为 反射 的语言功能。
相反,"manually" 构建元组或首先从元组开始。
或者,您可以在 Python(或类似的)中构建一个脚本来预处理您的代码和 auto-generate 生成的转换。
基于这些成员名称,即:第一个成员称为 a
,第二个 b
,第三个 c
。您可以定义以下结构模板 member_type<>
,以获取每个成员的类型:
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);
};
使用这个别名模板 tuple_splitter<>
,您可以从 struct
定义一个元组,其中包含这样的成员(名为 a
、b
和 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
>;
然后,对于你的Foo
:
tuple_splitter<Foo> foo_tuple;
foo_tuple
的类型为 std::tuple<float, int, double>
.
如果您现在定义一个新的 struct
、Bar
,如:
struct Bar { int a; char b; float c; };
然后:
tuple_splitter<Bar> bar_tuple;
bar_tuple
将是 std::tuple<int, char, float>
.
类型
你可以写一个转换运算符。
struct Test {
int a;
float b;
double c;
explicit operator std::tuple<int, float, double>() const {
return {a, b, c};
}
};
然后,像这样使用它:
int main() {
Test t{12, 3.2f, 4.5};
std::tuple tt = t;
}
使用 std::tie 甚至更容易:
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;
}
正如其他答案所说,在 C++14 中无法以通用方式执行此操作。
然而,C++17 中有一个使用结构化绑定的技巧:
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) );
此版本仅适用于具有 3 个成员的结构,但我相信通过一些时间和努力(以及一些 SFINAE),可以编写一个完全通用的解决方案(并且它可能会涉及很多 copy-paste).
问题很直接,我怎么生成:
std::tuple<float, int, double>
如果我知道类型:
struct Foo { float a; int b; double c; };
我如何在这两种转换中检索数据?
您可以手动完成。例如:
#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;
}
您不能在 C++ 中执行此操作,因为它需要一种称为 反射 的语言功能。
相反,"manually" 构建元组或首先从元组开始。
或者,您可以在 Python(或类似的)中构建一个脚本来预处理您的代码和 auto-generate 生成的转换。
基于这些成员名称,即:第一个成员称为 a
,第二个 b
,第三个 c
。您可以定义以下结构模板 member_type<>
,以获取每个成员的类型:
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);
};
使用这个别名模板 tuple_splitter<>
,您可以从 struct
定义一个元组,其中包含这样的成员(名为 a
、b
和 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
>;
然后,对于你的Foo
:
tuple_splitter<Foo> foo_tuple;
foo_tuple
的类型为 std::tuple<float, int, double>
.
如果您现在定义一个新的 struct
、Bar
,如:
struct Bar { int a; char b; float c; };
然后:
tuple_splitter<Bar> bar_tuple;
bar_tuple
将是 std::tuple<int, char, float>
.
你可以写一个转换运算符。
struct Test {
int a;
float b;
double c;
explicit operator std::tuple<int, float, double>() const {
return {a, b, c};
}
};
然后,像这样使用它:
int main() {
Test t{12, 3.2f, 4.5};
std::tuple tt = t;
}
使用 std::tie 甚至更容易:
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;
}
正如其他答案所说,在 C++14 中无法以通用方式执行此操作。
然而,C++17 中有一个使用结构化绑定的技巧:
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) );
此版本仅适用于具有 3 个成员的结构,但我相信通过一些时间和努力(以及一些 SFINAE),可以编写一个完全通用的解决方案(并且它可能会涉及很多 copy-paste).