连接元组作为类型
Concatenating tuples as types
我正在尝试练习一些模板编程。也许有一个标准的方法来做到这一点,我会很感激这样的答案,但我的主要目标是练习模板编程技术,所以我尝试自己实现它:
我需要连接多个元组,但作为类型,不像 std::cat_tuple
那样。所以我需要像 cat<std::tuple<int, float>, std::tuple<char, bool>, ...>
这样的东西来获得 std::tuple<int, float, char, bool, ...>
作为类型。
我当前的尝试因 is not a template
错误而失败:
/* Concat tuples as types: */
template <typename first_t, typename... rest_t> struct cat {
using type = typename _cat<first_t, typename cat<rest_t...>::type>::type;
^^^^ cat is not a template
};
template <typename first_t, typename second_t>
struct cat<first_t, second_t> {
using type = typename _cat<first_t, second_t>::type;
^^^^ cat is not a template
};
// Concat two tuples:
template <typename, typename> struct _cat;
template <typename tuple_t, typename first_t, typename... rest_t>
struct _cat<tuple_t, std::tuple<first_t, rest_t...>> {
using type = typename _cat<typename append<first_t, tuple_t>::type, std::tuple<rest_t...>>::type;
};
template <typename tuple_t, typename first_t>
struct _cat<tuple_t, std::tuple<first_t>> {
using type = typename append<first_t, tuple_t>::type;
};
// Prepend element to tuple:
template <typename, typename> struct prepend;
template <typename elem_t, typename... tuple_elem_t>
struct prepend<elem_t, std::tuple<tuple_elem_t...>> {
using type = std::tuple<elem_t, tuple_elem_t...>;
};
// Apppend element to tuple:
template <typename, typename> struct append;
template <typename elem_t, typename... tuple_elem_t>
struct append<elem_t, std::tuple<tuple_elem_t...>> {
using type = std::tuple<tuple_elem_t..., elem_t>;
};
可能导致错误的原因是什么?
这是一个好方法吗?它可能会以更简单的方式解决,但我希望它是多用途的(使用 append/prepend 操作等)。
稍微reordering定义之后,您的代码就可以正常工作了。
我认为模板元编程没有任何指导方针。可能是因为 C++ 委员会正在增强 TMP "aggressively" 而使用 TMP 的人太少了。
这是我的 Cat
版本,它基本上遵循与您的相同的结构:
template <class, class>
struct Cat;
template <class... First, class... Second>
struct Cat<std::tuple<First...>, std::tuple<Second...>> {
using type = std::tuple<First..., Second...>;
};
来不及玩了?
我提出以下解决方案
template <typename T, typename ...>
struct cat
{ using type = T; };
template <template <typename ...> class C,
typename ... Ts1, typename ... Ts2, typename ... Ts3>
struct cat<C<Ts1...>, C<Ts2...>, Ts3...>
: public cat<C<Ts1..., Ts2...>, Ts3...>
{ };
请注意,此解决方案不仅适用于 std::tuple
的可变列表,还适用于类型的通用容器。如果 std::tuple
-only 解决方案对您来说足够了,您可以按如下方式简化它
template <typename T, typename ...>
struct cat
{ using type = T; };
template <typename ... Ts1, typename ... Ts2, typename ... Ts3>
struct cat<std::tuple<Ts1...>, std::tuple<Ts2...>, Ts3...>
: public cat<std::tuple<Ts1..., Ts2...>, Ts3...>
{ };
您可以测试它是否适用于
using t1 = typename cat<std::tuple<int, float>,
std::tuple<char, bool>,
std::tuple<long, char, double>>::type;
using t2 = std::tuple<int, float, char, bool, long, char, double>;
static_assert(std::is_same<t1, t2>::value, "!");
-- 编辑--
正如 felix
所指出的(谢谢!),根据我的先例解决方案,我们有
std::is_same<int, typename cat<int>::type>::value == true
即...当 T
不是 std::tuple
时也定义了 cat<T>::type
。
这是个问题?
我不知道,因为我不知道如何使用cat<T>::type
。
无论如何...避免强加仅当所有Ts...
都是类型容器(具有相同容器)时才定义cat<Ts...>::type
,这很简单:cat
的主要版本变得只声明但未定义
template <typename, typename ...> // or also template <typename...>
struct cat;
并引入了单一类型的额外特化(但仅当它是类型容器时)。
template <template <typename ...> class C, typename ... Ts1>
struct cat<C<Ts1...>>
{ using type = C<Ts1...>; };
单行直接模板别名怎么样:
template<typename ... input_t>
using tuple_cat_t=
decltype(std::tuple_cat(
std::declval<input_t>()...
));
tuple_cat_t<
std::tuple<int,float>,
std::tuple<int>
> test{1,1.0f,2};
我正在尝试练习一些模板编程。也许有一个标准的方法来做到这一点,我会很感激这样的答案,但我的主要目标是练习模板编程技术,所以我尝试自己实现它:
我需要连接多个元组,但作为类型,不像 std::cat_tuple
那样。所以我需要像 cat<std::tuple<int, float>, std::tuple<char, bool>, ...>
这样的东西来获得 std::tuple<int, float, char, bool, ...>
作为类型。
我当前的尝试因 is not a template
错误而失败:
/* Concat tuples as types: */
template <typename first_t, typename... rest_t> struct cat {
using type = typename _cat<first_t, typename cat<rest_t...>::type>::type;
^^^^ cat is not a template
};
template <typename first_t, typename second_t>
struct cat<first_t, second_t> {
using type = typename _cat<first_t, second_t>::type;
^^^^ cat is not a template
};
// Concat two tuples:
template <typename, typename> struct _cat;
template <typename tuple_t, typename first_t, typename... rest_t>
struct _cat<tuple_t, std::tuple<first_t, rest_t...>> {
using type = typename _cat<typename append<first_t, tuple_t>::type, std::tuple<rest_t...>>::type;
};
template <typename tuple_t, typename first_t>
struct _cat<tuple_t, std::tuple<first_t>> {
using type = typename append<first_t, tuple_t>::type;
};
// Prepend element to tuple:
template <typename, typename> struct prepend;
template <typename elem_t, typename... tuple_elem_t>
struct prepend<elem_t, std::tuple<tuple_elem_t...>> {
using type = std::tuple<elem_t, tuple_elem_t...>;
};
// Apppend element to tuple:
template <typename, typename> struct append;
template <typename elem_t, typename... tuple_elem_t>
struct append<elem_t, std::tuple<tuple_elem_t...>> {
using type = std::tuple<tuple_elem_t..., elem_t>;
};
可能导致错误的原因是什么?
这是一个好方法吗?它可能会以更简单的方式解决,但我希望它是多用途的(使用 append/prepend 操作等)。
稍微reordering定义之后,您的代码就可以正常工作了。
我认为模板元编程没有任何指导方针。可能是因为 C++ 委员会正在增强 TMP "aggressively" 而使用 TMP 的人太少了。
这是我的 Cat
版本,它基本上遵循与您的相同的结构:
template <class, class>
struct Cat;
template <class... First, class... Second>
struct Cat<std::tuple<First...>, std::tuple<Second...>> {
using type = std::tuple<First..., Second...>;
};
来不及玩了?
我提出以下解决方案
template <typename T, typename ...>
struct cat
{ using type = T; };
template <template <typename ...> class C,
typename ... Ts1, typename ... Ts2, typename ... Ts3>
struct cat<C<Ts1...>, C<Ts2...>, Ts3...>
: public cat<C<Ts1..., Ts2...>, Ts3...>
{ };
请注意,此解决方案不仅适用于 std::tuple
的可变列表,还适用于类型的通用容器。如果 std::tuple
-only 解决方案对您来说足够了,您可以按如下方式简化它
template <typename T, typename ...>
struct cat
{ using type = T; };
template <typename ... Ts1, typename ... Ts2, typename ... Ts3>
struct cat<std::tuple<Ts1...>, std::tuple<Ts2...>, Ts3...>
: public cat<std::tuple<Ts1..., Ts2...>, Ts3...>
{ };
您可以测试它是否适用于
using t1 = typename cat<std::tuple<int, float>,
std::tuple<char, bool>,
std::tuple<long, char, double>>::type;
using t2 = std::tuple<int, float, char, bool, long, char, double>;
static_assert(std::is_same<t1, t2>::value, "!");
-- 编辑--
正如 felix
所指出的(谢谢!),根据我的先例解决方案,我们有
std::is_same<int, typename cat<int>::type>::value == true
即...当 T
不是 std::tuple
时也定义了 cat<T>::type
。
这是个问题?
我不知道,因为我不知道如何使用cat<T>::type
。
无论如何...避免强加仅当所有Ts...
都是类型容器(具有相同容器)时才定义cat<Ts...>::type
,这很简单:cat
的主要版本变得只声明但未定义
template <typename, typename ...> // or also template <typename...>
struct cat;
并引入了单一类型的额外特化(但仅当它是类型容器时)。
template <template <typename ...> class C, typename ... Ts1>
struct cat<C<Ts1...>>
{ using type = C<Ts1...>; };
单行直接模板别名怎么样:
template<typename ... input_t>
using tuple_cat_t=
decltype(std::tuple_cat(
std::declval<input_t>()...
));
tuple_cat_t<
std::tuple<int,float>,
std::tuple<int>
> test{1,1.0f,2};