#pragma once
#include <type_traits>

// 易用的工具宏
#define mp_arglist template		// 元函数参数列表开始
#define mp_arg typename			// 元函数参数声明
#define mp_function struct      // 元函数定义
#define mp_data typedef         // 元数据定义

#define mp_return(T) mp_data T type		// 元函数返回
// #define mp_return(T) using type = T
#define mp_exec(Func) Func::type		// 获取元函数返回结果
#define mp_eval(Func) Func::value		// 获取元函数返回值
#include <iostream>
#include <string>
#include <vector>
#include <deque>
#include <boost/type_traits.hpp>
#include "macros.h"

using namespace std;

// assert 函数
void assert(bool expression, std::string type)
{
	using namespace std;
	if (expression) cout << "is ";
	else cout << "is not ";
	cout << type << endl;
}

// 简单检查元函数类别
// 1、is_integral 检查元素是否为 bool char int long 只要沾边就行
// 2、is_floating_point 检查元素是否为 float、 double、 long double 等浮点型
// 3、is_void 检查类型是否为 void 类型
void test01()
{
	using namespace std;
	assert(mp_eval(is_integral<const char>), "integer");
	assert(mp_eval(is_integral<unsigned long>), "integer");
	assert(mp_eval(is_integral<int*>), "integer");	// 指针类型不是整型

	assert(mp_eval(is_floating_point<double>), "floating_point");
	assert(mp_eval(is_floating_point<float>), "floating_point");
	assert(mp_eval(is_floating_point<int>), "floating_point");

	assert(mp_eval(is_void<void>), "void");
	assert(mp_eval(is_void<void*>), "void");
}

// 检查其他类型
// 1、is_array 检查是否为原生数组
// 2、is_class 检查是否是一个class 或者struct
// 3、is_enum 检查是否为枚举
// 4、is_union 检查是否为联合类型
// 5、is_pointer 检查是否为指针类型或函数指针类型,但不是成员指针
// 6、is_function 检查T是否是一个函数类型,但不是函数指针或引用
// 7、is_lvalue_reference 检查是否为左值引用
// 8、is_rvalue_reference 检查是否为右值引用
void test02()
{
	assert(mp_eval(is_array<double[]>), "array");
	assert(mp_eval(is_array<int[2][3]>), "array");

	assert(mp_eval(is_class<struct dummy>), "class");
	assert(mp_eval(is_class<std::vector<int>>), "class");

	assert(mp_eval(is_pointer<int*>), "pointer");
	assert(mp_eval(is_pointer<int(*)(int)>), "pointer");

	assert(mp_eval(is_function<int(*)(int)>), "function");
	assert(mp_eval(is_function<void(int, double)>), "function");

	typedef float& float_ref;
	// 左值引用无论加多少&都是左值引用
	assert(mp_eval(is_lvalue_reference<float_ref>), "lvalue_reference");
	assert(mp_eval(is_lvalue_reference<float_ref&>), "lvalue_reference");
	assert(mp_eval(is_lvalue_reference<float_ref&&>), "lvalue_reference");
	assert(mp_eval(is_rvalue_reference<float&&>), "rvalue_reference");
}

// 检查成员指针类别
// 1、is_member_object_pointer 检查是否为指向成员变量的指针
// 2、is_member_function_pointer 检查是否为只想成员函数的指针
// 这里因为前面测试中定义过dummy同名宏,会导致后面用的时候检测不到成员,所以改名
struct dummy2
{
	int x;
	double y;
	void func() {}
};

void test03()
{
	int dummy2::* p = &dummy2::x;
	void (dummy2:: * funcPtr)() = &dummy2::func;
	assert(mp_eval(is_member_object_pointer<int dummy2::*>), "member_object_pointer");
	// 这里即使 dummy2 不含 char 类型成员也可以判断为真
	assert(mp_eval(is_member_object_pointer<char dummy2:: *>), "member_object_pointer");
	assert(mp_eval(is_member_function_pointer<void (dummy2:: *)()>), "member_function_pointer");
}

// 复合类别
// 1、is_reference 检查是否为引用类型
// 2、is_arithmetic 检查是否是算术类型 相当于 is_integral || is_floating_point
// 3、is_fundamental 检查是否是基本类型 相当于 is_arithmetic || is_void
// 4、is_compound 检查是否为复合类型,除非基本类型 相当于 !is_fundamental
// 5、is_member_pointer 检查是否是成员指针 包括指向成员变量和成员函数的指针 相当于 is_member_object_pointer || is_member_function_pointer
// 6、is_scalar 检查是否是标量类型 即算数类型 枚举 指针 和成员指针
// 7、is_object 检查是否是实体对象类型 即引用 void 和函数之外的所有类型
void test04()
{
	assert(mp_eval(is_reference<float&>), "reference");
	assert(mp_eval(is_reference<float&&>), "reference");
	assert(mp_eval(is_reference<std::deque<int> const&>), "reference");

	assert(mp_eval(is_arithmetic<char>), "arithmetic");
	assert(mp_eval(is_arithmetic<float volatile>), "arithmetic");
	assert(mp_eval(is_arithmetic<void const>), "arithmetic");

	assert(mp_eval(is_fundamental<void const>), "fundamental");

	assert(mp_eval(is_member_pointer<int(dummy2::*)>), "member_pointer");

	assert(mp_eval(is_compound<std::string>), "compound");

	assert(mp_eval(is_object<std::string>), "object");

	assert(mp_eval(is_scalar<int>), "scalar");
	assert(mp_eval(is_scalar<std::vector<int>>), "scalar");
}

// 元函数数据
// 1、is_const 是否被 const 修饰
// 2、is_volatile 是否被 volatile修饰
// 3、is_signed 检查是否有符号整数
// 4、is_unsigned 检查是否无符号整数
void test05()
{
	typedef const volatile int cv_int;

	assert(mp_eval(is_const<cv_int>), "const");
	assert(mp_eval(is_volatile<cv_int>), "volatile");
	assert(mp_eval(is_signed<cv_int>), "signed");
	assert(mp_eval(is_unsigned<cv_int>), "unsigned");
}

// 检查数组的属性
// 1、rank 返回数组的维数 多维数组返回第一个维度 不是数组返回0
// 2、extent<T,N> 返回数组的第N个维度的值 不是数组返回0
void test06()
{
	typedef const volatile int cv_int;

	assert(mp_eval(rank<int[2][3]>) == 2, "维度为2");

	assert(extent<int[2][3], 0>::value == 2, "第一个维度是否为2");
	assert(extent<int[2][3], 1>::value == 3, "第二个维度是否为3");
	// 不存在第三个维度 返回0
	assert(extent<int[2][3], 2>::value == 0, "第二个维度是否为0");
}

// 类相关属性
// 1、is_pod 是否为 POD 类型
// 2、is_empty 是否是一个空类
// 3、is_abstract 是否是一个抽象类
// 4、is_polymorphic 是否为一个多态类
// 5、is_final 检查T是否是一个final类
void test07()
{
	assert(mp_eval(is_pod<std::string>), "POD");
	assert(mp_eval(is_empty<std::plus<int>>), "empty");
	// 标准流是多态的
	assert(mp_eval(is_polymorphic<std::iostream>), "polymorphic");

	struct x final {};
	assert(mp_eval(is_abstract<x>), "abstract");
	assert(mp_eval(is_final<x>), "final");
}

// 操作符重载属性
// 1、has_greater 检查是否重载了 operator >
// 2、has_equal_to 检查是否重载了 operator =
// 3、has_less 检查是否重载了 operator <
// 4、has_plus 检查是否重载了 operator +
// 5、has_minus 检查是否重载了 operator -
// 6、has_pre_increment 检查是否重载了 前置 operator++
void test08()
{
	// has_less 使用需要加上boost::域解析运算符
	assert(mp_eval(boost::has_greater<int>), "greater");
	assert(mp_eval(boost::has_less<int>), "less");
	assert(mp_eval(boost::has_equal_to<int>), "equal_to");

	assert(mp_eval(boost::has_greater<std::string>), "greater");
	assert(mp_eval(boost::has_equal_to<std::string>), "equal_to");
	assert(mp_eval(boost::has_plus<std::string>), "plus");
	assert(mp_eval(boost::has_minus<std::string>), "minus");

	assert(mp_eval(boost::has_pre_increment<std::string::iterator>), "pre_increment");
}

// 元数据关系
// 1、is_same<T,U> 检查是否为相同类型
// 2、is_convertible 检查是否可隐式转型
// 3、is_base_of 检查是否为另一个类的基类 或者二者相同
// 4、is_virtual_base_of 检查是否为虚基类 
void test09()
{
	mp_data int meta_data1;
	mp_data int meta_data2;

	assert(is_same<int, meta_data1>::value, "int");
	assert(is_convertible<meta_data2, int>::value, "int");

	assert(is_base_of<std::string, std::string>::value, "base_of");
	assert(is_base_of<std::ios_base, std::iostream>::value, "base_of");

	assert(boost::is_virtual_base_of<std::ios_base, std::iostream>::value, "virtual_base_of");
	assert(boost::is_virtual_base_of<std::basic_ios<char>, std::iostream>::value, "virtual_base_of");
}

// 数据成员
// 基本的元数据加法
// 加法 为元数据添加 const volatile 指针 引用等修饰 返回变动后的新类型
// 1、add_const 返回 T const
// 2、add_volatile 返回 T volatile 
// 3、add_cv 返回 T const volatile
// 4、add_pointer 返回T*
// 5、add_lvalue_reference 对于对象或函数类型的返回左值引用 通常是 T& 否则返回T
// 6、add_rvalue_reference 对于对象或函数类型返回右值引用 通常是T&&  否则返回T 
void test10()
{
	mp_data mp_exec(add_const<int>) mdata1;

	assert(is_const<mdata1>::value, "const");
	assert(is_same<mdata1, int const>::value, "same");

	mp_data mp_exec(add_pointer<double>) mdata2;
	assert(boost::is_pointer<mdata2>::value, "pointer");
	assert(boost::is_same<mdata2, double*>::value, "same");

	mp_data mp_exec(add_lvalue_reference<mdata2>) mdata3;
	assert(is_lvalue_reference<mdata3>::value, "lvaule_reference");
	assert(boost::is_same<mdata3, double*&>::value, "same");

	mp_data mp_exec(add_lvalue_reference<void>) mdata4;
	assert(boost::is_void<mdata4>::value, "same");
}

// 基本的元数据减法  减法可以移除 cosnt volatile等
// 1、remove_const 移除顶层const修饰
// 2、renove_volatile 移除顶层的volatile 修饰
// 3、remove_cv 移除顶层const 和 volatile 修饰
// 4、remove_pointer 移除指针修饰
// 5、remove_reference 移除&& 或 &

// 特殊运算
// 处理算数类型
// 1、make_signed 返回相应的有符号整数类型  cv 修饰不变
// 2、make_unsigned 返回响应的无符号整数类型 cv 修饰不变
void test11()
{
	mp_data short const mdata1;

	mp_data mp_exec(make_signed<mdata1>) mdata2;
	assert(boost::is_const<mdata2>::value, "const");
	assert(boost::is_signed<short const>::value, "signed");
	assert(boost::is_signed<mdata2>::value, "signed");

	mp_data mp_exec(boost::make_unsigned<mdata2>) mdata3;
	assert(boost::is_same<mdata3, unsigned short const>::value, "same");
}

// 处理数组类型
// 1、remove_extent 移除顶层数组的最顶层维度 
// 2、remove_all_extent 移除数组的所有维度


// 其他运算
// 1、conditional<b,T,U> 条件运算 类似 ?: 造作根据b 的真假决定返回T或U
// 2、common_type<T,...> 求多个类型的共通类型 类似求数组的最小公倍数
void test12()
{
	mp_data common_type<int, char>::type mdata1;
	assert(boost::is_same<mdata1, int>::value, "same"); // int char共通类型是int
}

// 解析函数元数据
void test13()
{
	mp_data void(mdata1)(int, std::string); // 注意函数类型的定义方式

	assert(is_function<mdata1>::value, "function");

	const size_t n = boost::function_traits<mdata1>::arity;
	cout << "参数数量 : " << n << endl;

	mp_data boost::function_traits<mdata1>::result_type rType;
	assert(is_void<rType>::value, "void");

	mp_data boost::function_traits<mdata1>::arg2_type a2type;
	assert(is_same<a2type, std::string>::value, "string");
}

// integral_constant
void test14()
{
	assert(integral_constant<int, 10>::value == 10, "");
	assert(integral_constant<char, 0x30>::value == '0', "");
	assert(integral_constant<short, 100>::value == 100, "");
}

// is_integral
// 使用 typedef integral_constant<bool,true> true_type; 这种只返回true的元函数
// 通过继承 实现元函数转发 使其基础模板永恒返回 false 再 使用模板特化针对诸如 bool char 等类型返回true

// 应用示例 T* ? const T : const T*
mp_arglist<mp_arg T>
mp_function demo_func : conditional<is_pointer<T>::value,
	typename add_const<typename remove_pointer<T>::type>,
	typename add_pointer<typename add_const<T>::type>>
{};

// identity_type 把宏的参数转换为一个函数在返回

// declval 它用于在 不创建对象实例 的情况下,获取一个类型的“左值引用”或“右值引用”

int main()
{
	test14();
}