[英]Conversion between std::tuple and boost::tuple
Given a boost::tuple
and std::tuple
, how do you convert between them? 给定
boost::tuple
和std::tuple
,你如何在它们之间进行转换?
In other words, how would you implement the following two functions? 换句话说,您将如何实现以下两个功能?
template <typename... T> boost::tuple<T...> asBoostTuple( std::tuple<T...> stdTuple);
template <typename... T> std::tuple<T...> asStdTuple (boost::tuple<T...> boostTuple);
Seems to be a straightforward thing, but I could not find any good solutions. 似乎是一件简单的事情,但我找不到任何好的解决方案。
What did I try? 我尝试了什么?
I ended up solving it with template programming. 我最终用模板编程来解决它。 It seems to work in my concrete setup, but it does not feel right (too verbose), and I'm even not sure if it actually works in all situations (I'll come to that point later).
它似乎适用于我的具体设置,但它感觉不对(太冗长),我甚至不确定它是否真的适用于所有情况(我稍后会谈到这一点)。
Anyway, here is the interesting part: 无论如何,这是有趣的部分:
template<int offset, typename... T>
struct CopyStdTupleHelper
{
static void copy(boost::tuple<T...> source, std::tuple<T...>& target) {
std::get<offset>(target) = std::move(boost::get<offset>(source));
CopyStdTupleHelper<offset - 1, T...>::copy(source, target);
}
static void copy(std::tuple<T...> source, boost::tuple<T...>& target) {
boost::get<offset>(target) = std::move(std::get<offset>(source));
CopyStdTupleHelper<offset - 1, T...>::copy(source, target);
}
};
template<typename... T>
struct CopyStdTupleHelper<-1, T...>
{
static void copy(boost::tuple<T...> source, std::tuple<T...>& target)
{ /* nothing to do (end of recursion) */ }
static void copy(std::tuple<T...> source, boost::tuple<T...>& target)
{ /* nothing to do (end of recursion) */ }
};
std::tuple<T...> asStdTuple(boost::tuple<T...> boostTuple) {
std::tuple<T...> result;
CopyStdTupleHelper<sizeof...(T) - 1, T...>::copy(std::move(boostTuple), result);
return result;
}
boost::tuple<T...> asBoostTuple(std::tuple<T...> stdTuple) {
boost::tuple<T...> result;
CopyStdTupleHelper<sizeof...(T) - 1, T...>::copy(std::move(stdTuple), result);
return result;
}
I wonder if there is a more elegant way. 我想知道是否有更优雅的方式。 It seems like a very common operation to wrap existing APIs using
boost::tuple
to std::tuple
. 使用
boost::tuple
将现有API包装到std::tuple
似乎是一种非常常见的操作。
I tried to provide you with a minimal test example, where only the implementation of asBoostTuple
and asStdTuple
is missing. 我试图为您提供一个最小的测试示例,其中仅缺少
asBoostTuple
和asStdTuple
的实现。 However, for some magic with boost::tuples::null_type
, which I don't fully understand, it fails to compile. 但是,对于一些我不完全理解的
boost::tuples::null_type
魔法,它无法编译。 That is also the reason why I'm not sure that my existing solution can be generally applied. 这也是为什么我不确定我现有的解决方案是否可以普遍应用的原因。
Here is the snippet: 这是片段:
#include <tuple>
#include <boost/tuple/tuple.hpp>
template <typename... T>
boost::tuple<T...> asBoostTuple(std::tuple<T...> stdTuple) {
boost::tuple<T...> result;
// TODO: ...
return result;
}
template <typename... T>
std::tuple<T...> asStdTuple(boost::tuple<T...> boostTuple) {
std::tuple<T...> result;
// TODO: ...
return result;
}
int main() {
boost::tuple<std::string, int, char> x = asBoostTuple(std::make_tuple("A", 1, 'x'));
// ERROR:
std::tuple<std::string, int, char> y = asStdTuple<std::string, int, char>(x);
return x == y;
}
The error message is: 错误消息是:
example.cpp:20:38: error: no viable conversion from 'tuple<[3 *
...], boost::tuples::null_type, boost::tuples::null_type,
boost::tuples::null_type, boost::tuples::null_type,
boost::tuples::null_type, boost::tuples::null_type,
boost::tuples::null_type>' to 'tuple<[3 * ...], (no
argument), (no argument), (no argument), (no argument),
(no argument), (no argument), (no argument)>'
...int, char> y = asStdTuple<std::string, int, char>(x);
I understand that Boost's implementation is not based on variadic templates, which should explain the null_type
, but still I'm not sure how to avoid that compile error. 我理解Boost的实现不是基于可变参数模板,它应该解释
null_type
,但我仍然不确定如何避免编译错误。
The usual trick when doing this sort of manipulations is to construct an integer sequence and then use a pack expansion to initialize the new tuple. 执行此类操作时的常用技巧是构造整数序列,然后使用包扩展来初始化新元组。
The extra twist in this case is null_type
. 在这种情况下,额外的扭曲是
null_type
。 For that it's probably simplest to treat the tuple type as opaque, and manipulate it using boost::tuples::length
and boost::tuples::element
, which already handles null_type
properly. 为此,将元组类型视为不透明可能是最简单的,并使用
boost::tuples::length
和boost::tuples::element
来操作它,它已经正确处理了null_type
。 This way you do not rely on the implementation details of boost tuples. 这样您就不必依赖boost元组的实现细节了。
So: 所以:
template <typename StdTuple, std::size_t... Is>
auto asBoostTuple(StdTuple&& stdTuple, std::index_sequence<Is...>) {
return boost::tuple<std::tuple_element_t<Is, std::decay_t<StdTuple>>...>
(std::get<Is>(std::forward<StdTuple>(stdTuple))...);
}
template <typename BoostTuple, std::size_t... Is>
auto asStdTuple(BoostTuple&& boostTuple, std::index_sequence<Is...>) {
return std::tuple<typename boost::tuples::element<Is, std::decay_t<BoostTuple>>::type...>
(boost::get<Is>(std::forward<BoostTuple>(boostTuple))...);
}
template <typename StdTuple>
auto asBoostTuple(StdTuple&& stdTuple) {
return asBoostTuple(std::forward<StdTuple>(stdTuple),
std::make_index_sequence<std::tuple_size<std::decay_t<StdTuple>>::value>());
}
template <typename BoostTuple>
auto asStdTuple(BoostTuple&& boostTuple) {
return asStdTuple(std::forward<BoostTuple>(boostTuple),
std::make_index_sequence<boost::tuples::length<std::decay_t<BoostTuple>>::value>());
}
Note that the basic structure of the code is exactly identical for the two situations: we obtain the size of the tuple (via boost::tuples::length
or std::tuple_size
), construct an integer sequence using std::make_index_sequence
, and then use the integer sequence to obtain the types with boost::tuples::element
and std::tuple_element
, and the values with boost::get
/ std::get
. 请注意,代码的基本结构对于两种情况完全相同:我们获取元组的大小(通过
boost::tuples::length
或std::tuple_size
),使用std::make_index_sequence
构造整数序列,以及然后使用整数序列来获取带有boost::tuples::element
和std::tuple_element
,以及带有boost::get
/ std::get
。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.