迭代模板类型列表时无法停止递归
Can't stop recursion, while iterating a template type list
所以我有一个这样的模板类型列表:
template <typename... Types>
struct type_list
{
};
我做了一个这样的访问函数:
template<class TypeList, size_t ElementIndex>
struct at;
template <template<typename...> class TypeList, typename Head, typename... OtherTypes, size_t ElementIndex>
struct at< TypeList<Head, OtherTypes...>, ElementIndex>
{
static_assert(ElementIndex < (size_v< TypeList<Head, OtherTypes...> >), "at_t : ElementIndex is bigger than list size");
using type = if_else_t < ElementIndex == 0, Head, typename at< TypeList<OtherTypes...>, ElementIndex - 1 >::type >;
};
template <template<typename...> class TypeList, typename Last, size_t ElementIndex>
struct at< TypeList<Last>, ElementIndex>
{
static_assert(ElementIndex < (size_v< TypeList<Last> >), "at_t : ElementIndex is bigger than list size");
using type = Last;
};
template<class TypeList, size_t ElementIndex>
using at_t = typename at<TypeList, ElementIndex>::type;
if_else_t<>
具有以下实现:
template<bool Condition, typename True, typename False>
struct if_else
{
using type = True;
};
template<typename True, typename False>
struct if_else<false, True, False>
{
using type = False;
};
现在如果我用以下函数测试函数:
static_assert(std::is_same_v< bool, at_t< type_list<int, float, bool, char>, 2 > >, "at_t : Bad result");
我触发 static_assert 检查 ElementIndex 是否大于列表大小。
从编译器的输出我可以清楚地看到 at<>
永远不会停止递归,直到 ElementIndex 达到他的数值限制(ElementIndex = 0 - 1 的情况)并且 static_assert 被触发。
我做错了什么?
理想的答案还应该包括 at<>
的更好、更优雅的实现 :)
请注意,我使用的是 MSVC 和 C++17。
问题是当你这样做的时候:
if_else_t < ElementIndex == 0, Head, typename at< TypeList<OtherTypes...>, ElementIndex - 1 >::type >;
即使ElementIndex
是0
,其他两种类型仍然需要被评估才能传递给if_else_t
(从而触发static_assert
)。
您改用专业化来修复它:
template<class TypeList, size_t ElementIndex>
struct at;
template <template<typename...> class TypeList, typename Head, typename... OtherTypes>
struct at< TypeList<Head, OtherTypes...>, 0>
{
using type = Head;
};
template <template<typename...> class TypeList, typename Head, typename... OtherTypes, size_t ElementIndex>
struct at< TypeList<Head, OtherTypes...>, ElementIndex>
{
static_assert(ElementIndex < (size_v< TypeList<Head, OtherTypes...> >), "at_t : ElementIndex is bigger than list size");
using type = typename at< TypeList<OtherTypes...>, ElementIndex - 1 >::type;
};
template <template<typename...> class TypeList, size_t ElementIndex>
struct at< TypeList<>, ElementIndex>
{
static_assert(ElementIndex != ElementIndex, "at_t : ElementIndex is bigger than list size");
};
或者您可以使用标准 tuple_element
template<class TypeList, size_t ElementIndex>
struct at;
template <template<typename...> class TypeList, typename... Types, size_t ElementIndex>
struct at< TypeList<Types...>, ElementIndex>
{
static_assert(ElementIndex < (sizeof...(Types)), "at_t : ElementIndex is bigger than list size");
using type = std::tuple_element_t<ElementIndex, std::tuple<Types...>>;
};
作为旁注,if_else_t
只是 std::conditional_t
在
using type = if_else_t<ElementIndex == 0,
Head,
typename at<TypeList<OtherTypes...>, ElementIndex - 1>::type>;
typename at< TypeList<OtherTypes...>, ElementIndex - 1 >::type
必须评估。 at<TypeList<OtherTypes...>, ElementIndex - 1>
的实例化
您可能会延迟(并因此删除)实例化:
using type = typename if_else_t<ElementIndex == 0,
std::type_identity<Head>, // C++20, but trivial rewrite
at<TypeList<OtherTypes...>, ElementIndex - 1>>::type;
所以我有一个这样的模板类型列表:
template <typename... Types>
struct type_list
{
};
我做了一个这样的访问函数:
template<class TypeList, size_t ElementIndex>
struct at;
template <template<typename...> class TypeList, typename Head, typename... OtherTypes, size_t ElementIndex>
struct at< TypeList<Head, OtherTypes...>, ElementIndex>
{
static_assert(ElementIndex < (size_v< TypeList<Head, OtherTypes...> >), "at_t : ElementIndex is bigger than list size");
using type = if_else_t < ElementIndex == 0, Head, typename at< TypeList<OtherTypes...>, ElementIndex - 1 >::type >;
};
template <template<typename...> class TypeList, typename Last, size_t ElementIndex>
struct at< TypeList<Last>, ElementIndex>
{
static_assert(ElementIndex < (size_v< TypeList<Last> >), "at_t : ElementIndex is bigger than list size");
using type = Last;
};
template<class TypeList, size_t ElementIndex>
using at_t = typename at<TypeList, ElementIndex>::type;
if_else_t<>
具有以下实现:
template<bool Condition, typename True, typename False>
struct if_else
{
using type = True;
};
template<typename True, typename False>
struct if_else<false, True, False>
{
using type = False;
};
现在如果我用以下函数测试函数:
static_assert(std::is_same_v< bool, at_t< type_list<int, float, bool, char>, 2 > >, "at_t : Bad result");
我触发 static_assert 检查 ElementIndex 是否大于列表大小。
从编译器的输出我可以清楚地看到 at<>
永远不会停止递归,直到 ElementIndex 达到他的数值限制(ElementIndex = 0 - 1 的情况)并且 static_assert 被触发。
我做错了什么?
理想的答案还应该包括 at<>
的更好、更优雅的实现 :)
请注意,我使用的是 MSVC 和 C++17。
问题是当你这样做的时候:
if_else_t < ElementIndex == 0, Head, typename at< TypeList<OtherTypes...>, ElementIndex - 1 >::type >;
即使ElementIndex
是0
,其他两种类型仍然需要被评估才能传递给if_else_t
(从而触发static_assert
)。
您改用专业化来修复它:
template<class TypeList, size_t ElementIndex>
struct at;
template <template<typename...> class TypeList, typename Head, typename... OtherTypes>
struct at< TypeList<Head, OtherTypes...>, 0>
{
using type = Head;
};
template <template<typename...> class TypeList, typename Head, typename... OtherTypes, size_t ElementIndex>
struct at< TypeList<Head, OtherTypes...>, ElementIndex>
{
static_assert(ElementIndex < (size_v< TypeList<Head, OtherTypes...> >), "at_t : ElementIndex is bigger than list size");
using type = typename at< TypeList<OtherTypes...>, ElementIndex - 1 >::type;
};
template <template<typename...> class TypeList, size_t ElementIndex>
struct at< TypeList<>, ElementIndex>
{
static_assert(ElementIndex != ElementIndex, "at_t : ElementIndex is bigger than list size");
};
或者您可以使用标准 tuple_element
template<class TypeList, size_t ElementIndex>
struct at;
template <template<typename...> class TypeList, typename... Types, size_t ElementIndex>
struct at< TypeList<Types...>, ElementIndex>
{
static_assert(ElementIndex < (sizeof...(Types)), "at_t : ElementIndex is bigger than list size");
using type = std::tuple_element_t<ElementIndex, std::tuple<Types...>>;
};
作为旁注,if_else_t
只是 std::conditional_t
在
using type = if_else_t<ElementIndex == 0,
Head,
typename at<TypeList<OtherTypes...>, ElementIndex - 1>::type>;
typename at< TypeList<OtherTypes...>, ElementIndex - 1 >::type
必须评估。 at<TypeList<OtherTypes...>, ElementIndex - 1>
您可能会延迟(并因此删除)实例化:
using type = typename if_else_t<ElementIndex == 0,
std::type_identity<Head>, // C++20, but trivial rewrite
at<TypeList<OtherTypes...>, ElementIndex - 1>>::type;