到/从std :: tuple转换的结构 [英] struct to/from std::tuple conversion

查看:164
本文介绍了到/从std :: tuple转换的结构的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

假设我有 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆