我Typelist
用于分组类型。为此,我实现了一个元函数tlist_find_if
,它接受一个谓词Pred
和一个类型列表作为输入,如果条件匹配,则返回列表中包含的类型。
// template <typename... Ts>
struct tlist
{
using type = tlist;
static constexpr size_t size() noexcept { return sizeof...(Ts); }
};
template <template<typename T> typename Pred, typename TList>
struct tlist_find_if_impl;
template <template<typename T> typename Pred>
struct tlist_find_if_impl<Pred, tlist<>> { using result = null_t; };
template <template<typename T> typename Pred, typename H, typename... Ts>
struct tlist_find_if_impl<Pred, tlist<H, Ts...>>
{
using result = typename std::conditional<Pred<H>::value, H, typename tlist_find_if_impl<Pred, tlist<Ts...> >::result>::type;
};
// Wrapper
template <template <typename T> typename Pred, typename TList>
struct tlist_find_if;
template <template <typename T> typename Pred, typename... Ts>
struct tlist_find_if<Pred, tlist<Ts...>>
{
using result = typename tlist_find_if_impl<Pred, tlist<Ts...> >::result;
};
我还实现了一个元函数bind
来组合谓词:
template <template <typename...> typename F, typename T>
struct bind
{
template <typename... Ts>
using type = F<T, Ts...>;
};
但是在使用它时,编译器要么接受所有内容,要么给出错误。
没有错误的示例:
int main()
{
// ...
using type = tlist_find_if<bind<std::is_same, a1_t>::type, x_group >::result; // , x_group>;
static_assert(std::is_same_v<a1_t, type>);
}
与特定类型一起使用时没有错误。但是在模板元函数中使用时,编译器会抛出错误。
template <typename Group>
struct type_in_group_pred
{
static constexpr bool value = std::is_same<Group, typename tlist_find_if<bind<std::is_same, T>::type, Group>::result>::value; // Ошибка!
};
using group = typename tlist_find_if<type_in_group_pred, GroupList>::result;
错误文字:
main2.cc:107:117: error: type/value mismatch at argument 1 in template parameter list for ‘template<template<class T> class Pred, class TList> struct tlist_find_if’
107 | static constexpr bool value = std::is_same<Group, typename tlist_find_if<bind<type_in_group, T>::type, Group>::result>::value;
| ^
main2.cc:107:116: error: type/value mismatch at argument 1 in template parameter list for ‘template<template<class T> class Pred, class TList> struct tlist_find_if’
107 | static constexpr bool value = std::is_same<Group, typename tlist_find_if<bind<std::is_same, T>::type, Group>::result>::value;
| ^
main2.cc:107:116: note: expected a class template, got ‘bind<std::is_same, T>::type’
也就是说,由于某种原因,编译器将 bind 的结果读取为具体类型,而不是模板。但为什么?在没有错误的示例中,一切正常。
供复制的样本测试程序的全文
#include <type_traits>
#include <stdio.h>:
struct a1_t { int x; };
struct a2_t { int x; };
struct b1_t { int y; };
struct b2_t { int y; };
struct c1_t { int z; };
struct c2_t { int z; };
struct null_t {};
template <typename... Ts>
struct tlist
{
using type = tlist;
static constexpr size_t size() noexcept { return sizeof...(Ts); }
};
template <template<typename T> typename Pred, typename TList>
struct tlist_find_if_impl; // { using result = null_t; };
template <template<typename T> typename Pred>
struct tlist_find_if_impl<Pred, tlist<>> { using result = null_t; };
template <template<typename T> typename Pred, typename H, typename... Ts>
struct tlist_find_if_impl<Pred, tlist<H, Ts...>>
{
using result = typename std::conditional<Pred<H>::value, H, typename tlist_find_if_impl<Pred, tlist<Ts...> >::result>::type;
};
// Wrapper
template <template <typename T> typename Pred, typename TList>
struct tlist_find_if;
template <template <typename T> typename Pred, typename... Ts>
struct tlist_find_if<Pred, tlist<Ts...>>
{
using result = typename tlist_find_if_impl<Pred, tlist<Ts...> >::result;
};
template <typename T, typename U>
struct null_t_wrap
{
using type = typename std::conditional<std::is_same_v<null_t, T>, U, T>::type;
};
template <template <typename...> typename F, typename T>
struct bind
{
template <typename... Ts>
using type = F<T, Ts...>;
};
using null_group = tlist<>;
using x_group = tlist<a1_t, a2_t>;
using y_group = tlist<b1_t, b2_t>;
using group_tlist = tlist<x_group, y_group>;
template <typename T>
struct null_setter { static void set(T& t, int x) { (void)t; (void)x; printf("null setter x = %d\n", x); } };
template <typename T>
struct x_setter { static void set(T& t, int x) { t.x = x; printf("set x = %d\n", x); } };
template <typename T>
struct y_setter { static void set(T& t, int y) { t.y = y; printf("set y = %d\n", y); } };
template <typename T, typename Group>
struct group_2_setter { using setter = null_setter<T>; };
template <typename T>
struct group_2_setter<T, x_group> { using setter = x_setter<T>; };
template <typename T>
struct group_2_setter<T, y_group> { using setter = y_setter<T>; };
template <typename T, typename Group>
struct type_2_group
{
template <typename H>
struct type_is_same_pred
{
static constexpr bool value = std::is_same<T, H>::value;
};
// using group = typename null_t_wrap<typename tlist_find_if<type_is_same_pred, Group>::result, null_group>::type;
using group = typename tlist_find_if<type_is_same_pred, Group>::result;
};
template <typename T, typename Group>
struct type_in_group
{
template <typename U>
struct is_t
{
static constexpr bool value = std::is_same_v<T, U>;
};
static constexpr bool value = std::is_same<T, typename tlist_find_if<is_t, Group>::result>::value;
};
template <typename T, typename GroupList>
struct group_list_2_group
{
template <typename Group>
struct type_in_group_pred
{
// static constexpr bool value = std::is_same<Group, typename type_2_group<T, Group>::group >::value;
static constexpr bool value = std::is_same<Group, typename tlist_find_if<bind<std::is_same, T>::type, Group>::result>::value;
};
// using group = typename null_t_wrap<typename tlist_find_if<type_in_group_pred, GroupList>::result, null_group>::type;
// using group = typename tlist_find_if<type_in_group_pred, GroupList>::result;
using group = typename tlist_find_if<type_in_group_pred, GroupList>::result;
};
template <typename T, typename GroupList>
struct type_2_setter
{
using setter = typename group_2_setter<T, typename group_list_2_group<T, GroupList>::group>::setter;
};
int main()
{
a1_t a1;
a2_t a2;
b1_t b1;
b2_t b2;
c1_t c1;
c2_t c2;
using is_same_as_a1_t = bind<std::is_same, a1_t>::type<a1_t>;
static_assert(is_same_as_a1_t::value);
// using a1_t_setter = type_2_setter<a1_t, group_tlist>::setter;
// a1_t_setter::set(a1, 1);
// using group = type_2_group<a1_t, x_group>;
// printf("%s\n", typeid(group).name());
// static_assert(std::is_same_v<group, null_t>);
// using a2_t_setter = type_2_setter<a2_t, group_tlist>::setter;
// a2_t_setter::set(a2, 2);
// using b1_t_setter = type_2_setter<b1_t, group_tlist>::setter;
// b1_t_setter::set(b1, 1);
using b2_t_setter = type_2_setter<b2_t, group_tlist>::setter;
b2_t_setter::set(b2, 2);
// using c1_t_setter = type_2_setter<c1_t, group_tlist>::setter;
// c1_t_setter::set(c1, 2);
using type = tlist_find_if<bind<std::is_same, a1_t>::type, x_group >::result; // , x_group>;
static_assert(std::is_same_v<a1_t, type>);
static_assert(std::is_same_v<a1_t, tlist_find_if<bind<std::is_same, a1_t>::type, x_group>::result>);
}