文章目錄
- C++之type_traits
- is_floating_point<T> ..的使用
- std::enable_if<T>::type的使用
- std::remove_cv
- 如何自定義traits
C++之type_traits
is_floating_point …的使用
- 一般在定義打印模板函數的時候,當我們用printf進行終端日志打印,需要根據打印的類型來設置flag,所以這個時候判斷數據類型就很必要了, 我們可以根據is_same,is_float_point, is_integral等來確定類型情況。可以參考cuda打印實例
std::is_floating_point<yourtype>::value;std::is_same<type1, type2>::value;
- 這些is_xxx的函數,如何定義的; 有什么可以學習的點
std::enable_if::type的使用
- c++的原則就替換失敗并非錯誤(SFINAE)。std::enable_if 就是滿足條件時類型是有效的
- 所謂的SFINAE規則就是在編譯時進行查找替換,對于重載的函數,如果能夠找到合適的就會替換,如果第一個不合適并不會報錯,而會使用下一個替換直到最后一個,如果都不滿足要求,那么才會報錯。出現二義性的話也會報錯。
- 主要兩個應用
- 類型判斷,可以自定義類型判斷
//判斷類型
template <typename _Tp>
struct Smart_pointer : public false_type {};template <typename _Tp>
struct Smart_pointer<std::weak_ptr<_Tp>> : public true_type {};template <typename _Tp>
struct Smart_pointer<std::shared_ptr<_Tp>> : public true_type {};template <typename _Tp>
struct is_smart_pointer : public Smart_pointer<typename std::remove_cv<_Tp>::type>{};template <typename _Tp>
typename enable_if<is_smart_pointer<_Tp>::value,void>::type check(_Tp p){std::cout << "is smart pointer" << std::endl;
}
template <typename _Tp>
typename enable_if<!is_smart_pointer<_Tp>::value,void>::type check(_Tp p){std::cout << "not smart pointer" << std::endl;
}
void test_enable_if(){int *p = new int(3);std::shared_ptr<int> sp = std::make_shared<int>(3);check(sp);check(p);delete p;
}
- 返回值指定,根據輸入類型判斷返回值
template <typename _Tp>typename enable_if<std::is_integral<_Tp>::value,bool>::type is_odd(_Tp i){return i&0x1;}void test_is_odd(){std::cout << std::boolalpha << is_odd(10) << std::endl;}
-
Apollo開源代碼中的一個實例; 利用C++的SFINAE原則,實現在類的繼承過程中,上層類中定義一個必執行的函數,里面調用子類可能實現可能不實現的具體函數,這個時候就用到了這個特性,通過模板推導機制,實現子類定義這個具體操作時,這個必執行的函數會調用這個具體操作,當沒有定義是,就按照這個必執行函數的默認操作去執行。
-
Apollo 開源代碼示例分析-HasShutdown
#include <type_traits>
#include <utility>// apollo: cyber/base/macros.h
#define DEFINE_TYPE_TRAIT(name, func) \template <typename T> \struct name { \template <typename Class> \static constexpr bool Test(decltype(&Class::func)*) { \return true; \} \template <typename> \static constexpr bool Test(...) { \return false; \} \\static constexpr bool value = Test<T>(nullptr); \}; \\template <typename T> \constexpr bool name<T>::value;// apollo: cyber/common/macros.h
/**
template <typename T>
struct HasShutdown {template <typename Class>static constexpr bool Test(decltype(&Class::Shutdown)*) {return true;}template <typename>static constexpr bool T(...) {return false;}static constexpr bool value = Test<T>(nullptr);
};
template <typename T>
constexpr bool HasShutdown<T>::value;*/
DEFINE_TYPE_TRAIT(HasShutdown, Shutdown)template <typename T>
typename std::enable_if<HasShutdown<T>::value>::type CallShutdown(T *instance) {instance->Shutdown();
}template <typename T>
typename std::enable_if<!HasShutdown<T>::value>::type CallShutdown(T *instance) {(void)instance; // 可以自定義任何默認的動作。
}/** 分析
1. 當instance實例的類中有Shudown時,第一個模板中HasShutdown<T>::value是true,則enable_if<true>::type是合法的;則第一個模板函數被匹配;而此時!HasShutdown<T>::value是false,則第二個模板函數匹配有問題,所以根據C++的SFINAE原則,則第一個被推導出來;所以當調用CallShutdown時,第一個函數被調用,而其有會調用instance中的shutdown函數。
3. 反之,當instance中沒有shutDown,則第一個的HasShutdown<T>::value是false,則std::enable_if<HasShutdown<T>::value>::type非法,所以第一個模板不能被推導出來,而第二個模板被推導出來,所以當調用CallShutdown時,第二個函數形式被調用;從而這就實現了,當有Shutdown的時候調用自己定義的,否則不做任何事情。
*/// 下面是CallShutdown被使用時的場景, 通過在一個單例中cleanup里調用,來實現用戶定制或不定制的情況。
#define DECLARE_SINGLETON(classname) \public: \static classname *Instance(bool create_if_needed = true) { \static classname *instance = nullptr; \if (!instance && create_if_needed) { \static std::once_flag flag; \std::call_once(flag, \[&] { instance = new (std::nothrow) classname(); }); \} \return instance; \} \\static void CleanUp() { \auto instance = Instance(false); \if (instance != nullptr) { \CallShutdown(instance); \} \} \\private: \classname(); \DISALLOW_COPY_AND_ASSIGN(classname)
std::remove_cv
- 去掉變量的const, volatile屬性,獲取其原始類型信息。
實現方式
- 模版推導丟棄const和volatile參數。
性能開銷
- 模版推導完成操作,不涉及運行時開銷。
調用stl
- remove_const
- remove_volatile
作者:i_need_job
鏈接:https://www.jianshu.com/p/a771299d3a89
來源:簡書