判斷兩個類型的關系
#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;
}
可以通過編譯期的判斷式來選擇類型,這給我們動态選擇類型提供了很大的靈活性