由于愚蠢的原因,我不会进入这里,我需要注释掉的线路才能工作,上面的线条不起作用:
template<uint _N, typename... _Args>
struct PartialTuple;
template<uint _N, typename _Arg, typename... _Args>
struct PartialTuple<_N, _Arg, _Args...>: PartialTuple<_N-1, _Args...> {};
template<typename _Arg, typename... _Args>
struct PartialTuple<0, _Arg, _Args...>
{
typedef std::tuple<_Arg, _Args...> type;
};
int main()
{
// I want this to not work...
PartialTuple<1, std::string, std::string, int, int>::type A{"test", 5, 1};
// I want this to work...
//PartialTuple<1, std::string, std::string, int, int>::type B{"test", "test", 5};
}
我尝试用_Arg
交换_Args...
,但这不会编译(至少在GCC 4.6中):
error: parameter pack argument ‘_Args ...’ must be at the end of the template argument list
如何从尾巴而不是从头部拉出物品?
答案 0 :(得分:5)
这是一个解决方案:我只是从前面截断N
,而不是从后面截断sizeof...(Args) - N
:
#include <tuple>
/* Concatenator helper */
template <typename T, typename Tuple> struct cat;
template <typename T, typename ...Args>
struct cat<T, std::tuple<Args...>>
{
typedef typename std::tuple<T, Args...> value;
};
/* Head-of-tuple */
template <unsigned int, typename...> struct tuple_head;
// Base case. Need to specialize twice, once for one and once for variadic types
template <typename ...Args>
struct tuple_head<0, Args...>
{
typedef std::tuple<> value;
};
template <typename T>
struct tuple_head<0, T>
{
typedef std::tuple<> value;
};
// Recursion step
template <unsigned int N, typename T, typename ...Args>
struct tuple_head<N, T, Args...>
{
typedef typename cat<T, typename tuple_head<N - 1, Args...>::value>::value value;
};
/* User interface */
template <unsigned int N, typename ...Args>
struct PartialTuple
{
typedef typename tuple_head<sizeof...(Args) - N, Args...>::value type;
};
/* Usage */
#include <string>
int main()
{
// I want this to not work...
//PartialTuple<1, std::string, std::string, int, int>::type A{"test", 5, 1};
// I want this to work...
PartialTuple<1, std::string, std::string, int, int>::type B("test", "test", 5);
PartialTuple<0, std::string, std::string, int, int>::type C("test", "test", 5, 6);
}
答案 1 :(得分:3)
我整晚都在玩它,终于有了一些工作(改变了我的外壳以匹配STL):
template<uint _N, typename... _All>
struct reverse_tuple_outer
{
template<typename _Head, typename... _Tail>
struct reverse_tuple_inner: reverse_tuple_outer<_N-1, _Head, _All...>::template reverse_tuple_inner<_Tail...> { };
};
template<typename... _All>
struct reverse_tuple_outer<0, _All...>
{
template<typename... _Tail>
struct reverse_tuple_inner {
typedef std::tuple<_All...> type;
};
};
template<typename... _Args>
struct reverse_tuple
{
typedef typename reverse_tuple_outer<sizeof...(_Args)>::template reverse_tuple_inner<_Args...>::type type;
};
template<typename... _Args>
struct strip_and_reverse_tuple;
template<typename... _Args>
struct strip_and_reverse_tuple<std::tuple<_Args...>>
{
typedef typename reverse_tuple<_Args...>::type type;
};
template<uint _N, typename... _Args>
struct partial_tuple
{
typedef typename strip_and_reverse_tuple<typename reverse_tuple_outer<sizeof...(_Args)-_N>::template reverse_tuple_inner<_Args...>::type>::type type;
};
int main()
{
//partial_tuple<1, std::string, std::string, int, int>::type A{"test", 5, 1};
partial_tuple<1, std::string, std::string, int, int>::type B{"test", "test", 5};
}
作为一个额外的奖励,我也有reverse_tuple
,我是否需要它。
答案 2 :(得分:3)
我的代码工作有点像Haskell中的列表 - 因为,TMP是C ++中纯粹的函数式语言。
add_to_pack
等同于Haskell的列表构造函数(:)
。 drop_from_end
实现为(在Haskell表示法中)\x list -> take (length list - x) list
,其中take n
只占用列表的第一个n
元素。
我想您可以直接使用std::tuple
而不是pack
,但我更喜欢这个解决方案,因为它不会滥用元组作为模板参数包持有者。 :)
以下是代码:
#include <tuple>
#include <type_traits> // for std::conditional
template <typename... Pack>
struct pack
{ };
template <typename, typename>
struct add_to_pack;
template <typename A, typename... R>
struct add_to_pack<A, pack<R...>>
{
typedef pack<A, R...> type;
};
template <typename>
struct convert_to_tuple;
template <typename... A>
struct convert_to_tuple<pack<A...>>
{
typedef std::tuple<A...> type;
};
template <int, typename...>
struct take;
template <int N>
struct take<N>
{
typedef pack<> type;
};
template <int N, typename Head, typename... Tail>
struct take<N, Head, Tail...>
{
typedef
typename std::conditional<
(N > 0),
typename add_to_pack<
Head,
typename take<
N - 1,
Tail...
>::type
>::type,
pack<>
>::type type;
};
template <int N, typename... A>
struct drop_from_end
{
// Add these asserts if needed.
//static_assert(N >= 0,
// "Cannot drop negative number of elements!");
//static_assert(N <= static_cast<int>(sizeof...(A)),
// "Cannot drop more elements than size of pack!")
typedef
typename convert_to_tuple<
typename take<
static_cast<int>(sizeof...(A)) - N,
A...
>::type
>::type type;
};
int main()
{
drop_from_end<2, const char*, double, int, int>::type b{"pi", 3.1415};
}
以下是工作中的代码:via ideone.com。
take
结构或多或少等同于遵循Haskell代码:
take n [] = []
take n (x:xs)
| n > 0 = x : take (n - 1) xs
| otherwise = []
答案 3 :(得分:0)
我使用Boost.MPL和Boost.Fusion做了类似的事情:使用push_back
等MPL工具计算类型序列,然后使用fusion::vector
将其转换为fusion::as_vector
并且MPL适配器。我已经有了帮助,可以将fusion::vector
转换为std::tuple
。