C++ 实现一个type list 模板,在编译期计算。这个type list主要有构造,列表头类型,列表尾类型,concat操作,去除列表元素重复,获取指定元素,删除指定元素的操作。实现代码贴在下面:
cpp
复制代码
#pragma once
#include <iostream>
#include <typeinfo>
namespace type_list {
// Step 1: 基础类型列表定义
// 定义空列表
template <typename ...Types>
struct list {};
// 非空列表的递归定义
template <typename Type, typename ...Types>
struct list<Type, Types...> {
using head = Type;
using tail = list<Types...>;
};
// 定义空列表类型
using empty_list = list<>;
// Step 2: 获取列表头部类型
template <typename TypeList>
using head_t = typename TypeList::head;
// 获取列表尾部类型
template <typename TypeList>
using tail_t = typename TypeList::tail;
// 构造新列表
template <typename Head, typename Tail>
struct construct;
template <typename Head, typename Tail>
using construct_t = typename construct<Head, Tail>::type;
template <typename Head, typename ...Types>
struct construct<Head, list<Types...>> {
using type = list<Head, Types...>;
};
///
template<typename TypeList>
struct size;
// 模板辅助类
template<typename TypeList>
constexpr size_t size_v = size<TypeList>::value;
//size的模板特化,继承了std::integral_constant
template<typename...Types>
struct size<list<Types...>> : std::integral_constant<std::size_t, sizeof...(Types)> {};
template<class TypeList>
constexpr bool empty_v = (size_v<TypeList> == 0);
template<class TypeList>
struct empty : std::bool_constant<empty_v<TypeList>> {};
template<class TypeList>
constexpr bool empty_s = empty<TypeList>::value;
/
// 查找模板的制定索引的value
//声明一个模板;
template<std::size_t Index, class TypeList>
struct get;
template<std::size_t Index, class TypeList>
using get_t = typename get<Index, TypeList>::type;
template<std::size_t Index, class TypeList>
struct get {
using type = get_t<Index - 1, tail_t<TypeList>>;
};
template<class TypeList>
struct get<0, TypeList> {
using type = head_t<TypeList>;
};
/
// concat
template<typename TypeList1, typename TypeList2>
class concat;
template<typename T, typename U>
using concat_t = typename concat<T, U>::type;
template<typename ...T, typename ...U>
class concat<list<T...>, list<U...>> {
public:
using type = list<T..., U...>;
};
// delete specific type
template<typename TypeList, typename Type>
class remove_all;
template<typename TypeList, typename Type>
using remove_all_t = typename remove_all<TypeList, Type>::type;
template<typename TypeList, typename Type>
class remove_all {
public:
using head = head_t<TypeList>;
using tail = tail_t<TypeList>;
using clean_tail = remove_all_t<tail, Type>;
using type = std::conditional_t<std::is_same_v<head, Type>, clean_tail, construct_t<head, clean_tail>>;
};
template<typename Type>
class remove_all<empty_list, Type> {
public:
using type = empty_list;
};
// get the last type
template<typename TypeList>
class last;
template<typename TypeList>
using last_t = typename last<TypeList>::type;
template<typename TypeList>
class last {
public:
using type = last_t<tail_t<TypeList>>;
};
// 递归终止
template<typename Type>
class last<list<Type>> {
public:
using type = Type;
};
// distinct list type
template<typename TypeList>
class distinct;
template<typename TypeList>
using distinct_t = typename distinct<TypeList>::type;
template <typename TypeList>
class distinct{
public:
using type = construct_t<
head_t<TypeList>,
distinct_t<
remove_all_t<tail_t<TypeList>, head_t<TypeList>>>>;
};
// 递归终止
template <>
struct distinct<empty_list> {
using type = empty_list;
};
// print list
template<typename T>
void print_type() {
int status;
std::cout << typeid(T).name() << std::endl;
}
// 打印类型列表
template <typename TypeList>
struct print_list;
template <typename TypeList>
void print_list_func() {
print_list<TypeList>::print();
}
// 主模板,递归地打印类型列表
template <typename TypeList>
struct print_list {
static void print() {
print_type<head_t<TypeList>>();
print_list_func<tail_t<TypeList>>();
}
};
// 终止递归的特化版本
template <>
struct print_list<empty_list> {
static void print() {
// 空列表,不打印任何内容
}
};
} // namespace type_list
测试代码
cpp
复制代码
#pragma once
#include "type_list.h"
#include <iostream>
using namespace std;
void test_type_list() {
//1.define list
using MyList = type_list::list<int, double, char>;
using AnotherList = type_list::list<float, int>;
using EmptyList = type_list::list<>;
//2. get the head and tail type of list
using MyListHead = type_list::head_t<MyList>;
using MyListTail = type_list::tail_t<MyList>;
static_assert(std::is_same_v<MyList::tail, type_list::list<double,char>>, "MyList head shoud be int");
static_assert(std::is_same_v<MyListTail, type_list::list<double, char>>, "MyList head shoud be int");
static_assert(std::is_same_v<MyListHead, int>, "MyList head shoud be int");
static_assert(std::is_same_v<MyList::head, int>, "MyList head shoud be int");
//3. get list size
constexpr std::size_t listSize = type_list::size_v<MyList>;
std::cout << listSize << std::endl;
// 4. empty
static_assert(type_list::empty_s<EmptyList>, "is empty");
static_assert(type_list::empty_v<EmptyList>, "is empty");
// 5. get index pos
using FirstType = type_list::get_t<1, MyList>;
static_assert(std::is_same_v<FirstType, double>, "not equal");
// 6.concat list
using ConcatList = type_list::concat_t<MyList, AnotherList>;
using ConcatListHead = type_list::head_t<ConcatList>;
static_assert(std::is_same_v<ConcatListHead, int>, "head should be int");
static_assert(std::is_same_v<ConcatList::head, int>, "head should be int");
constexpr std::size_t concat_list_size = type_list::size_v<ConcatList>;
cout << "concat_list_size : " << concat_list_size << endl;
// 6.delete list type
using RemoveIntList = type_list::remove_all<MyList, int>;
static_assert(std::is_same_v<type_list::head_t<RemoveIntList>, int>, "the list head shoud not be int");
// 6.delete list type
using LastType = type_list::last_t<MyList>;
static_assert(std::is_same_v<LastType, char>, "the last type should be char");
// distinct list type
using RepeatList = type_list::list<int, double, char, int, double, char, int,int,int>;
using DistType = type_list::distinct_t<RepeatList>;
std::cout << "--------------------------" << endl;
type_list::print_list_func<RepeatList>();
std::cout << "--------------------------" << endl;
type_list::print_list_func<DistType>();
std::cout << "--------------------------" << endl;
}