到/从std :: tuple转换的结构 [英] struct to/from std::tuple conversion
问题描述
假设我有 struct
和 std :: tuple
具有相同类型的布局:
Assuming I have struct
and std::tuple
with same type layout:
struct MyStruct { int i; bool b; double d; }
using MyTuple = std::tuple<int,bool,double>;
有没有一种标准的方法可以将彼此投射?
Is there any standartized way to cast one to another?
PS我知道微不足道的内存复制可以解决问题,但这取决于对齐方式和实现
P.S. I know that trivial memory copying can do the trick, but it is alignment and implementation dependent
推荐答案
不幸的是,没有自动方法可以为此,但另一种方法是使结构适应Boost.Fusion序列。对于每个新类,您将一劳永逸。
Unfortunately there is no automatic way to do that, BUT an alternative is adapt the struct to Boost.Fusion sequence. You do this once and for all for each new class.
#include <boost/fusion/adapted/struct/adapt_struct.hpp>
...
struct MyStruct { int i; bool b; double d; }
BOOST_FUSION_ADAPT_STRUCT(
MyStruct,
(int, i)
(bool, b)
(double, d)
)
使用 MyStruct
就像使用Fusion .sequence(如果使这些函数通用,则该序列几乎适合您已经使用过 std :: tuple< ...>
的所有位置。)作为奖励,您不需要完全复制您的数据成员。
The use MyStruct
as if it where a Fusion.Sequence (it fits generically almost everywhere you already use std::tuple<...>
, if you make those functions generic.) As a bonus you will not need to copy your data members at all.
如果您确实需要转换为 std :: tuple
,请在融合之后-adapting,您可以执行以下操作:
If you really need to convert to std::tuple
, after "Fusion-adapting" you can do this:
#include <boost/fusion/adapted/std_tuple.hpp>
#include <boost/fusion/algorithm/iteration/for_each.hpp>
#include <boost/fusion/algorithm/transformation/zip.hpp>
...
auto to_tuple(MyStruct const& ms){
std::tuple<int, bool, double> ret;
auto z = zip(ret, ms);
boost::fusion::for_each(z, [](auto& ze){get<0>(ze) = get<1>(ze);});
// or use boost::fusion::copy
return ret;
}
事实是 std :: tuple
是半支持功能。就像拥有STD容器而没有算法一样。 Fortunatelly我们有 #include< boost / fusion / adapted / std_tuple.hpp>
,我们可以做一些很棒的事情。
The truth is that std::tuple
is a half-backed feature. It is like having STD containers and no algorithms. Fortunatelly we have #include <boost/fusion/adapted/std_tuple.hpp>
that allows us to do amazing things.
完整代码:
包含来自Boost.Fusion std_tuple.hpp
标头> std :: tuple 自动适应Boost.Fusion序列,因此通过使用Boost.Fusion作为结构体和 std :: tuple
:
By including the std_tuple.hpp
header from Boost.Fusion std::tuple
is automatically adapted to a Boost.Fusion sequence, thus the following is possible by using Boost.Fusion as a bridge between your struct and std::tuple
:
#include <iostream>
#include <string>
#include <tuple>
#include <boost/fusion/adapted/struct/adapt_struct.hpp>
#include <boost/fusion/algorithm/auxiliary/copy.hpp>
#include <boost/fusion/adapted/std_tuple.hpp>
struct foo
{
std::string a, b, c;
int d, e, f;
};
BOOST_FUSION_ADAPT_STRUCT(
foo,
(std::string, a)
(std::string, b)
(std::string, c)
(int, d)
(int, e)
(int, f)
)
template<std::size_t...Is, class Tup>
foo to_foo_aux(std::index_sequence<Is...>, Tup&& tup) {
using std::get;
return {get<Is>(std::forward<Tup>(tup))...};
}
template<class Tup>
foo to_foo(Tup&& tup) {
using T=std::remove_reference_t<Tup>;
return to_foo_aux(
std::make_index_sequence<std::tuple_size<T>{}>{},
std::forward<Tup>(tup)
);
}
template<std::size_t...Is>
auto to_tuple_aux( std::index_sequence<Is...>, foo const& f ) {
using boost::fusion::at_c;
return std::make_tuple(at_c<Is>(f)...);
}
auto to_tuple(foo const& f){
using T=std::remove_reference_t<foo>;
return to_tuple_aux(
std::make_index_sequence<boost::fusion::result_of::size<foo>::type::value>{},
f
);
}
int main(){
foo f{ "Hello", "World", "!", 1, 2, 3 };
std::tuple<std::string, std::string, std::string, int, int, int> dest = to_tuple(f);
// boost::fusion::copy(f, dest); // also valid but less general than constructor
std::cout << std::get<0>(dest) << ' ' << std::get<1>(dest) << std::get<2>(dest) << std::endl;
std::cout << at_c<0>(dest) << ' ' << at_c<1>(dest) << at_c<2>(dest) << std::endl; // same as above
foo f2 = to_foo(dest);
std::cout << at_c<0>(f2) << ' ' << at_c<1>(f2) << at_c<2>(f2) << std::endl;
}
我将不建议 reinterpret_cast< std :: tuple< ...>&>(mystructinstance.i)
,因为这将导致反对票不能携带。
I will not recommend reinterpret_cast<std::tuple<...>&>(mystructinstance.i)
because that will result in negative votes and it is not portable.
这篇关于到/从std :: tuple转换的结构的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!