我有一个元组类型。我想在其中添加元素类型以获得新的元组类型。我可以像
那样做decltype tuple_cat(MyTuple, std::tuple<MyType>())
但是,我在tuple_cat
中找不到boost::tuple
,如何在提升中找到它?
答案 0 :(得分:7)
我假设你在编译时想要这一切。
以下是一般性解释:连接元组类似于连接列表或数组,是算法是相同的。在这里,给定元组a
和b
,我选择将a
的最后一个元素移到b
的开头,然后重复,直到a
为空。
第一:基础结构。以下结构保留参数包。它可以是任何东西,例如元组:
template<typename... T>
struct pack
{
static const unsigned int size = sizeof...(T);
};
请注意,包的大小存储在其中。它不是强制性的,但它便于解释。 Boost使用struct boost::tuples::length<T>::value
(更详细)。
要访问第i个位置的元素,我们使用类似于boost::tuples::element<n, T>
的结构:
// Get i-th element of parameter pack
// AKA 'implementation'
// Principle: the element i is the first element of the sub-array starting at indice i-1
template<int n, typename F, typename... T>
struct element_at : public element_at<n-1, T...>
{
};
template<typename F, typename... T>
struct element_at<0, F, T...>
{
typedef F type;
};
// Get i-th element of pack
// AKA 'interface' for the 'pack' structure
template<int n, typename P>
struct element
{
};
template<int n, typename... T>
struct element<n, pack<T...>>
{
typedef typename element_at<n, T...>::type type;
};
现在,我们必须使用一个低级操作,即将一个元素添加到包的一侧(在左侧或右侧添加)。这里选择左边添加,但它不是唯一的选择:
// Concat at left (only for structure 'pack')
template<typename a, typename b>
struct tuple_concat_left
{
};
template<typename a, typename... b>
struct tuple_concat_left<a, pack<b...>>
{
typedef pack<a, b...> type;
};
对于模板,a
不会更改,而是我们使用indice来了解要添加的元素。继承定义了一个'type'typedef,它是n
和另一个元组(不包括n
之后的所有索引的串联,并且按顺序)。我们只需要在indice n
处左侧连接元素。
// Concat 2 tuples
template<typename a, typename b, int n = 0, bool ok = (n < a::size)>
struct tuple_concat : public tuple_concat<a, b, n+1>
{
typedef typename tuple_concat_left<
typename element<n, a>::type,
typename tuple_concat<a, b, n+1>::type
>::type type;
};
template<typename a, typename b, int n>
struct tuple_concat<a, b, n, false>
{
typedef b type;
};
就是这样! Live example here
现在,对于元组细节:你注意到我没有使用boost :: tuple和std :: tuple。这是因为boost tuples的许多实现都无法访问可变参数模板,因此使用了固定数量的模板参数(默认为boost::tuples::null_type
)。直接使用可变参数模板这很令人头疼,因此需要进行另一种抽象。
我还假设您可以使用C ++ 11(在您的问题中使用decltype
)。在C ++ 03中连接2个元组是可能的,但更重复和无聊。
您可以非常轻松地将pack
转换为元组:只需将pack
定义更改为:
template<typename... T>
struct pack
{
static const unsigned int size = sizeof...(T);
typedef boost::tuple<T...> to_tuple; // < convert this pack to a boost::tuple
};
答案 1 :(得分:1)
C ++ 14提供了一个库,用于在编译类型中生成一个整数序列。这有助于操作静态序列,如元组和数组(example)。 可以获得整数序列
template<size_t... Ints>
struct integer_sequence {};
template<size_t Size, size_t... Ints>
struct implementation : implementation<Size-1, Size-1, Ints...> {};
template<size_t... Ints>
struct implementation<0, Ints...>
{
typedef integer_sequence<Ints...> type;
};
template<class... T>
using index_sequence_for = typename implementation<sizeof...(T)>::type;
要结束MyTuple
和MyType
,您可以编写简单的函数:
template<typename X, typename Tuple, size_t... Ints>
auto concat(X x, Tuple t, integer_sequence<Ints...>)
-> decltype( std::make_tuple(x, std::get<Ints>(t)...) )
{
return std::make_tuple(x, std::get<Ints>(t)...);
}
template<typename X, typename... T>
std::tuple<X, T...> concat(X x, std::tuple<T...> t)
{
return concat(x, t, index_sequence_for<T...>());
}
concat(MyType, MyTuple);