判断两个类型的关系
#include <iostream> #include <type_traits> using std::cout; using std::endl; // is_same is used to judge two data types same or not during compiling void test_is_same() { cout << "test is_same:" << endl; cout << std::is_same<int, int>::value << endl; cout << std::is_same<int, unsigned int>::value << endl; cout << std::is_same<int, signed int>::value << endl; } // is_base_of is used to judge the relationship between two data types is inheritance namespace test_is_base_of { class A { }; class B : A { }; class C { }; void test_is_base_of() { cout << "test is_base_of:" << endl; cout << std::is_base_of<A, B>::value << endl; cout << std::is_base_of<B, A>::value << endl; cout << std::is_base_of<C, B>::value << endl; } }; // is_convertible is used to judge if the first parameter data type could be converted to the second parameter data type namespace test_is_convertible { class A { }; class B : public A { }; class C { }; void test_is_convertible() { cout << "test is_convertible:" << endl; bool b2a = std::is_convertible<B *, A *>::value; bool a2b = std::is_convertible<A *, B *>::value; bool b2c = std::is_convertible<B *, C *>::value; cout << std::boolalpha; cout << b2a << endl; cout << a2b << endl; cout << b2c << endl; } }; int main(void) { test_is_same(); test_is_base_of::test_is_base_of(); test_is_convertible::test_is_convertible(); return 0; }
类型转换
#include <iostream> #include <type_traits> using std::cout; using std::endl; /* 常用的类型转换traits const的添加与移除 引用的添加与移除 数组的修改和指针的修改 */ void base_using() { cout << std::boolalpha; // 添加const cout << std::is_same<const int, std::add_const<int>::type>::value << endl; // 移除const cout << std::is_same<int, std::remove_const<const int>::type>::value << endl; // 添加左值引用 cout << std::is_same<int &, std::add_lvalue_reference<int>::type>::value << endl; // 添加右值引用 cout << std::is_same<int &&, std::add_rvalue_reference<int>::type>::value << endl; // 移除左值引用 cout << std::is_same<int, std::remove_reference<int &>::type>::value << endl; // 移除右值引用 cout << std::is_same<int, std::remove_reference<int &&>::type>::value << endl; // 添加指针 cout << std::is_same<int *, std::add_pointer<int>::type>::value << endl; // 移除数组顶层维度 cout << std::is_same<int, std::remove_extent<int[]>::type>::value << endl; cout << std::is_same<int[2], std::remove_extent<int[][2]>::type>::value << endl; cout << std::is_same<int[2][3], std::remove_extent<int[][2][3]>::type>::value << endl; cout << std::is_same<int[2][3], std::remove_extent<int[4][2][3]>::type>::value << endl; // 移除数组所有维度 cout << std::is_same<int, std::remove_all_extents<int[][2][3]>::type>::value << endl; // 取公共类型 typedef std::common_type<unsigned char, short, int>::type NumericType; cout << std::is_same<int, NumericType>::value << endl; } int main(void) { base_using(); return 0; }
注意,根据模板参数类创建对象时,要注意移除引用
创建对象是需要使用原始类型,不能使用引用类型,而模板参数T可能是引用类型,所以需要提前移除可能存在的引用
// attention! 根据模板参数类创建对象时,要注意移除引用 template <typename T> typename std::remove_reference<T>::type *Create() { typedef typename std::remove_reference<T>::type U; return new U(); }
添加和移除引用实例
#include <iostream> #include <type_traits> #include <memory> using std::cout; using std::endl; // 有时需要添加引用类型,比如从智能指针中获取对象的引用时 template <class T> struct Construct { // step1: 去掉引用,将去掉引用的数据类型定义为U typedef typename std::remove_reference<T>::type U; // step3: 创建构造函数 Construct() : m_ptr(new U) { } // step4: 获取成员变量值,加上引用和const typename std::add_lvalue_reference<U>::type Get() const { return *m_ptr.get(); } private: // step2: 用定义的数据类型U std::unique_ptr<U> m_ptr; }; int main() { Construct<int> c; int a = c.Get(); cout << a << endl; return 0; }
decay
对于有cv(const/volatile)操作符修饰的变量很难直接取到他的原始类型,所以西药先移除引用,再移除cv运算符,方法如下
template <typename T> typename std::remove_cv<typename std::remove_reference<T>::type>::type *Create() { typedef typename std::remove_cv<typename std::remove_reference<T>::type>::type U; return new U(); }
但是这么写实在是太长了,所以有了decay,decay不光可以处理普通变量,还可以处理函数和数组,他的处理逻辑如下
1.移除引用
2.判断是不是数组,如果是数组,把数组编程数组指针,结束
3.否则 判断是不是函数,如果是函数,把函数变成函数指针,结束
4.如果都不是,移除cv符(普通变量)
void test_decay() { cout << std::boolalpha; cout << std::is_same<int, std::decay<int>::type>::value << endl; cout << std::is_same<int, std::decay<int &>::type>::value << endl; cout << std::is_same<int, std::decay<int &&>::type>::value << endl; cout << std::is_same<int, std::decay<const int &>::type>::value << endl; cout << std::is_same<int *, std::decay<int[2]>::type>::value << endl; cout << std::is_same<int (*)(int), std::decay<int(int)>::type>::value << endl; }
std::decay对于函数来说是添加指针,利用这一点可以将函数变成函数指针,从而将函数指针变量保存起来,在后面延迟执行
template <typename F> struct SimpFunction { using FnType = typename std::decay<F>::type; SimpFunction(F &f) : m_fn(f) {} void Run() { m_fn(); } FnType m_fn; };
编译期选择std::conditional<bool B,class T, class F>
在std::conditional的模板参数中,B如果为true,则conditional::type为T, 否则为F
#include <iostream> #include <type_traits> using std::cout; using std::endl; void test_conditional() { using A = std::conditional<true, int, float>::type; using B = std::conditional<false, int, float>::type; cout << std::boolalpha; cout << std::is_same<int, A>::value << endl; cout << std::is_same<float, B>::value << endl; cout << std::is_same<long, std::conditional<std::is_integral<A>::value, long, int>::type>::value << endl; cout << std::is_same<int, std::conditional<std::is_integral<B>::value, long, int>::type>::value << endl; // 比较两个类型,输出较大的类型 using max_size_t = std::conditional<(sizeof(long long) > sizeof(long double)), long long, long double>::type; cout << typeid(max_size_t).name() << endl; } int main(void) { test_conditional(); return 0; }
可以通过编译期的判断式来选择类型,这给我们动态选择类型提供了很大的灵活性