日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > c/c++ >内容正文

c/c++

C++类型萃取之type_traits和type_info

發布時間:2025/3/8 c/c++ 18 豆豆
生活随笔 收集整理的這篇文章主要介紹了 C++类型萃取之type_traits和type_info 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

  • 類型萃取
    • 類型判斷
    • typeid
    • decltype和declval
    • enable_if

類型萃取

通過type_traits可以實現在編譯期計算、查詢、判斷、轉換和選擇,增強了泛型編程的能力,也增強了我們程序的彈性,讓我們能夠在編譯期就能夠優化改進甚至排錯,進一步提高代碼質量。

頭文件 #include

類型判斷

type_trits提供了豐富的編譯期計算、查詢、判斷、轉換和選擇的幫助類,在很多場合中會使用到這些特性。

type_trits的類型選擇功能,在一定程度上可以消除冗長的switch-case或者if-else的語句,降低程序的復雜程度。

這些類型判斷的方法從std::integral_constant派生,用來檢查模板類型是否為某種類型,通過這些trait可以獲取編譯期檢查的bool值結果。

下面的表格是一些常用的判斷類型traits。更過從網址 點擊獲取。

traits類型說明
template
struct is_void;
T是否為void類型
template
struct is_floating_point;
T是否為浮點類型
template
struct is_array;
T是否為數組類型
template
struct is_pointer;
T是否為指針類型(包括函數指針,但不包括成員(函數)指針)
template
struct is_enum;
T是否為枚舉類型
template
struct is_union;
T是否為非union的class/struct類型
template
struct is_class;
T是否為類類型而不是union類型
template
struct is_funtion;
T是否為函數類型
template
struct is_reference;
T是否為引用類型(左值引用或者右值引用)
template
struct is_arithmetic;
T是否為整型和浮點類型
template
struct is_fundamental;
T是否為整型、浮點、void、或nullptr_t類型
template
struct is_object;
T是否為一個對象類型(不是函數、不是引用、不是void)
template
struct is_scalar;
T是否為arithmetic、enumeration、pointer、pointer to member或std::nullptr_t類型
template
struct is_compound;
T是否非fundamental類型構造的
template
struct is_member_pointer;
T是否為成員函數指針類型
template
struct is_polymorphic;
T是否有虛函數
template
struct is_abstract;
T是否為抽象類
template
struct is_signed;
T是否是有符號類型
template
struct is_unsigned;
T是否是無符號類型
template
struct is_const;
T是否為const修飾的類型

使用方法:

#include <iostream> #include <type_traits>int main() {std::cout << "is_const:" << std::endl;std::cout << "int: " << std::is_const<int>::value << std::endl;std::cout << "const int: " << std::is_const<const int>::value << std::endl;return 0; }輸出結果為: is_const: int: 0 const int: 1

判斷類型的traits一般和std::enable_if結合起來使用,通過SFINAE特性來實現功能更強大的重載。后面會講到。

判斷兩個類型之間的關系traits

traits說明
template
struct is_same;
判斷兩個類型是否相同
template
struct is_base_of;
判斷Base類型是否為Derived類型的基類
template
struct is_convertible;
判斷前面的模板參數類型能否轉換為后面的模板參數類型

簡單介紹一下is_same的用法:

#include <iostream> #include <type_traits>int main() {std::cout << "int: " << std::is_same<int, int>::value << std::endl;//這里使用了decltype可以獲取變量的類型為intstd::cout << "int: " << std::is_same<decltype(a), int>::value << std::endl;std::cout << "const int: " << std::is_same<int, unsigned int>::value << std::endl;return 0; }輸出結果為: int: 1 int: 1 const int: 0

類型的轉換traits

常用的類型轉換traits包括對const的修改—-const的移除和添加,引用的修改—–引用的移除和添加,數組的修改和指針的修改。

下表為類型轉換的方法:

traits說明
template
struct remove_const;
移除const
template
struct add_const;
添加const
template
struct remove_reference;
移除引用
template
struct add_lvalue_reference;
添加左值引用
template
struct add_rvalue_reference;
添加右值引用
template
struct remove_extents;
移除數組頂層的維度
template
struct remove_all_extents;
移除數組所有的維度
template
struct remove_pointer;
移除指針
template
struct add_pointer;
添加指針
template
struct decay;
移除cv或添加指針
template
struct common_type;
獲取公共類型

簡單介紹一下使用方法:

具體可以參考c++11深入理解93頁。

#include <iostream> #include <type_traits>int main() {std::cout << "int: " << std::is_same<int, add_const<int>>::value << std::endl;return 0; }輸出結果為: int: 0

typeid

包含頭文件 #include

在講解typeid神秘面紗之前,我們先了解一下,RTTI(Run-Time Type Identification),中文為運行時類型識別,它使程序能夠獲取由基指針或引用所指向的對象的實際派生類型。即允許 “用指向基類的指針或引用來操作對象” 的程序能夠獲取到 “這些指針或引用所指對象” 的實際派生類型。

在C++中,為了支持RTTI提供了兩個操作符:dynamic_cast和typeid。

  • dynamic_cast允許運行時刻進行類型轉換,從而使程序能夠在一個類層次結構中安全地轉化類型,與之相對應的還有一個非安全的轉換操作符static_cast,因為這不是本文的討論重點,所以這里不再詳述,感興趣的可以自行查閱資料。
  • typeid是C++的關鍵字之一,等同于sizeof這類的操作符。typeid操作符的返回結果是名為type_info的標準庫類型的對象的引用。

我們來看一下如何使用:

#include <typeinfo>struct Base { virtual ~Base() = default; }; struct Derived : Base {};int main() {Base b1;Derived d1;const Base *pb = &b1;std::cout << typeid(*pb).name() << '\n';pb = &d1;std::cout << typeid(*pb).name() << '\n';std::cout << typeid(1).name() << '\n';std::cout << typeid(2.444).name() << '\n';return 0; }輸出結果: 4Base 7Derived i d

上面是在gcc編譯上編譯的,結果與vc++,clang都大不相同。

decltype和declval

有時候要獲取函數的返回類型是一件比較困難的事情:
比如下面代碼:

template <typename F, typename Arg> ?? func(F f, Arg arg) {return f * arg; }

由于函數的入參都是兩個模板參數,導致我們不能直接確定返回類型,那么我們可以通過decltype來推斷函數返回類型。

template <typename F, typename Arg> decltype((*(F*)0)*((*(Arg*)0))) func(F f, Arg arg) {return f * arg; }

上面的比較繁瑣,所以我們可以使用返回類型后置去簡化。

template <typename F, typename Arg> auto func(F f, Arg arg)->decltype(f * arg ) {return f * arg; }

這樣看起來就舒服多了。

但是有些時候我們不能通過decltype來獲取類型了,如下面:

#include <type_traits>class A {A()=delete; public:int operator() ( int i ){return i;} };int main() {int a = A()(3);decltype( A()(0) ) i = 4;std::cout << i << std::endl;std::cout << a << std::endl; //輸出結果為3return 0; }

上面的代碼將會編譯報錯,因為A沒有默認構造函數,對于這種沒有默認構造函數的類型,我們如果希望能推導其成員函數的返回類型,則需要借助std::declval。

修改為:

decltype( std::declval<A>()(std::declval<int>())) i = 4;

上面的代碼可以通過,因為std::declval能夠獲取任何類型的臨時值,不管它有沒有默認構造函數。因為我們通過declval()獲取了A的臨時對象。需要注意一點,declval獲取的臨時值不能用于求值,因此必須使用decltype來推斷出最終的返回類型。

其實上面做了這么多,還是比較麻煩,C++11提供了另外一個trait——std::result_of,用來在編譯期獲取一個可調用對象的返回類型。

上面的代碼改寫如下:

std::result_of<A(int)>::type i = 4;

這段代碼實際上等價于 decltype( std::declval()(std::declval()))。

enable_if

在講enable_if之前我們先來了解什么是SFINAE,它是Substitution failure is not an error 的首字母縮寫。

我們通過一個例子來了解一下SFINAE機制:

template<typename T> void Fun(T *t) {*t *+= 1; }template<typename T> void Fun(T t) {t += 1; }int main() {Fun(1);return 0; }

上面運行的時候,將會匹配到第二個重載函數,在匹配的過程中,當匹配到void Fun(T t)時,將一個非0的整數來替換T 是錯誤的,此時編譯器并不會報錯,此時就叫failure,然后繼續匹配其他的重載函數,如果最后發現void Fun(T t)能匹配上,整個過程就不會報錯,如果匹配不到就會報error,這就是為什么叫Substitution failure is not an error。

這個規則就叫SFINAE

std::enable_if利用SFINAE實現根據條件選擇重載函數,std::enable_if的原型如下:

template<bool B, class T = void> struct enable_if;

簡單介紹一下使用的方法

//is_arithmetic為判斷是否為整型和浮點類型的traits //這里在使用的時候需要加上typename在enable_if前面 //是要告訴編譯器后面的標識符是一個類型名來處理,否則會被編譯器當做靜態變量處理 template<class T> typename std::enable_if<std::is_arithmetic<T>::value, T>::type foo(T t) {return t; }int main() {auto r = foo(1);auto r1 = foo(1.2);std::cout << r <<std::endl; //1,整數std::cout << r1 <<std::endl; //1.2,浮點數//auto r2 = foo("test"); //編譯錯誤return 0; }

上面的函數模板通過enable_if做了限定,只能接受整型和浮點型,我們來看一下foo(1)運行步驟:

1. 根據傳入的實參1,推斷出T為int類型 2. std::is_arithmetic<T>::value變為std::is_arithmetic<int>::value,此時返回值為true 3. std::enable_if<std::is_arithmetic<T>::value, T>中的最后一個T為int,通過::type獲取類型。 4. foo函數的返回值被確定為int類型

總結

以上是生活随笔為你收集整理的C++类型萃取之type_traits和type_info的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。