判断两个类型的关系
#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;
}
可以通过编译期的判断式来选择类型,这给我们动态选择类型提供了很大的灵活性
无情的摸鱼机器