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

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

decltype 和 auto

發布時間:2024/4/18 编程问答 40 豆豆
生活随笔 收集整理的這篇文章主要介紹了 decltype 和 auto 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

返回類型推導 decltype

?

decltype 推導規則

編譯器將根據以下三條規則得出結果:

  • 如果 exp 是一個不被括號( )包圍的表達式,或者是一個類成員訪問表達式,或者是一個單獨的變量,那么 decltype(exp) 的類型就和 exp 一致,這是最普遍最常見的情況。
  • 如果 exp 是函數調用,那么 decltype(exp) 的類型就和函數返回值的類型一致。
  • 如果 exp 是一個左值,或者被括號( )包圍,那么 decltype(exp) 的類型就是 exp 的引用;假設 exp 的類型為 T,那么 decltype(exp) 的類型就是 T&。
【實例】exp 是左值,或者被( )包圍: using namespace std; class Base{ public:int x; }; int main(){const Base obj;//帶有括號的表達式decltype(obj.x) a = 0; //obj.x 為類的成員訪問表達式,符合推導規則一,a 的類型為 intdecltype((obj.x)) b = a; //obj.x 帶有括號,符合推導規則三,b 的類型為 int&。//加法表達式int n = 0, m = 0;decltype(n + m) c = 0; //n+m 得到一個右值,符合推導規則一,所以推導結果為 intdecltype(n = n + m) d = c; //n=n+m 得到一個左值,符號推導規則三,所以推導結果為 int&return 0; }

用法

在難以或不可能以標準寫法進行聲明的類型時,decltype 很有用,例如 lambda 相關類型或依賴于模板形參的類型。C++11新標準引入了decltype類型說明符,它的作用是選擇并返回操作數的數據類型,在此過程中,編譯器分析表達式并得到它的類型,卻不實際計算表達式的值。

據我自己的理解,這個關鍵字經常被用在模板編程中,模板在使用時,可能會出現不知道應該聲明是什么類型的狀況

template<typename?T1,typename?T2>?type? fun(T1 a,T2 b){ ?type? aplusb=a+b;????return?aplusb;}

在上述情況中,我們事先并不知道aplusb的類型,無法對其進行聲明。
但是C++11中新增加的關鍵字decltype解決了這個問題

template<typename T1,typename T2>auto?fun(T1?a,T2?b)?->decltype(a+b)?//auto?馬上會講{????return?aplusb=a+b;}

為什么函數的返回值是auto嘞?由于在提供返回類型之前,還未聲明變量a,b所以無法對返回類型設置為decltype(a,b)
這時候在C++11中提供了一個解決方案,就是后置返回類型。簡單的說就是把返回值后置。

例子

#include?<iostream>struct A { double x; };const?A*?a;decltype(a->x) y; // y 的類型是 double(其聲明類型)decltype((a->x))?z?=?y;?//?z?的類型是?const?double&(左值表達式)???template<typename T, typename U>auto add(T t, U u) -> decltype(t + u) // 返回類型依賴于模板形參{ // C++14 開始可以推導返回類型 return t+u;}int main() { int i = 33;????decltype(i)?j?=?i?*?2; std::cout << "i = " << i << ", "??????????????<<?"j?=?"?<<?j?<<?'\n'; auto f = [](int a, int b) -> int { return a * b;????}; decltype(f) g = f; // lambda 的類型是獨有且無名的 i = f(2, 2);????j?=?g(3,?3); std::cout << "i = " << i << ", " << "j = " << j << '\n';}

輸出:

i = 33, j = 66i = 4, j = 9

decltype 的實際應用

auto 的語法格式比 decltype 簡單,所以在一般的類型推導中,使用 auto 比使用 decltype 更加方便,本節僅演示只能使用 decltype 的情形。
我們知道,auto 只能用于類的靜態成員,不能用于類的非靜態成員(普通成員),如果我們想推導非靜態成員的類型,這個時候就必須使用 decltype 了。下面是一個模板的定義:

#include <vector> using namespace std;template <typename T> class Base { public:void func(T& container) {m_it = container.begin(); }private:typename T::iterator m_it; //注意這里 };int main() {const vector<int> v;Base<const vector<int>> obj;obj.func(v);return 0; }

單獨看 Base 類中 m_it 成員的定義,很難看出會有什么錯誤,但在使用 Base 類的時候,如果傳入一個 const 類型的容器,編譯器馬上就會彈出一大堆錯誤信息。原因就在于,T::iterator并不能包括所有的迭代器類型,當 T 是一個 const 容器時,應當使用 const_iterator。

要想解決這個問題,在之前的 C++98/03 版本下只能想辦法把 const 類型的容器用模板特化單獨處理,增加了不少工作量,看起來也非常晦澀。但是有了 C++11 的 decltype 關鍵字,就可以直接這樣寫:

template <typename T> class Base { public:void func(T& container) {m_it = container.begin(); }private:decltype(T().begin()) m_it; //注意這里 };

看起來是不是很清爽?

注意,有些低版本的編譯器不支持T().begin()這種寫法,以上代碼我在 VS2019 下測試通過,在 VS2015 下測試失敗。

?

類型推導之 auto

用法?

C++11中,auto不再是一個存儲類型指示符,而是一個自動推導變量的類型。auto并非是一種類型的聲明,而是一個類型聲明時的“占位符”編譯器在編譯期間會將auto替換為變量實際的類型

我覺得auto給我們帶來的最大改變有兩方面。

  • ?解放程序員雙手。有了auto這個神器,媽媽再也不用擔心我的鍵盤手了。auto可以代替以前要打的很長很長的變量類型

  • 還是用在模板推導,下邊的例子如果沒有auto,x*y就沒有辦法填寫類型了。

  • template <typename _Tx,typename _Ty>void Multiply(_Tx x, _Ty y){ auto v = x*y; std::cout << v;}

    需要注意的是:

    • auto 變量必須在定義時初始化,這類似于const關鍵字。

    • 如果初始化表達式是引用,則去除引用語義

    • 如果初始化表達式為const或volatile(或者兩者兼有),則除去const/volatile語義

    • 如果auto關鍵字帶上&號,則不去除const語意

    const int a2 = 10;auto?&b2?=?a2;//因為auto帶上&,故不去除const,b2類型為const?int
    • 初始化表達式為數組時,auto關鍵字推導類型為指針

    • 若表達式為數組且auto帶上&,則推導類型為數組類型

    • 函數或者模板參數不能被聲明為auto

    void func(auto a) //錯誤{ //... }
    • 時刻要注意auto并不是一個真正的類型。auto僅僅是一個占位符,它并不是一個真正的類型,不能使用一些以類型為操作數的操作符,如sizeof或者typeid

    cout << sizeof(auto) << endl;//錯誤cout?<<?typeid(auto).name()?<<?endl;//錯誤

    例子

    #include <iostream>#include?<utility>template<class T, class U>auto?add(T?t,?U?u)?{?return?t?+?u;?}?//?返回類型是?operator+(T,?U)?的類型// 在其所調用的函數返回引用的情況下// 函數調用的完美轉發必須用 decltype(auto)template<class F, class... Args>decltype(auto) PerfectForward(F fun, Args&&... args) { return fun(std::forward<Args>(args)...); }template<auto n> // C++17 auto 形參聲明auto f() -> std::pair<decltype(n), decltype(n)> // auto 不能從花括號初始化器列表推導{ return {n, n};}int main(){ auto a = 1 + 2; // a 的類型是 int auto b = add(1, 1.2); // b 的類型是 double static_assert(std::is_same_v<decltype(a), int>);????static_assert(std::is_same_v<decltype(b),?double>); auto c0 = a; // c0 的類型是 int,保有 a 的副本 decltype(auto) c1 = a; // c1 的類型是 int,保有 a 的副本 decltype(auto) c2 = (a); // c2 的類型是 int&,為 a 的別名 std::cout << "a, before modification through c2 = " << a << '\n'; ++c2;????std::cout?<<?"a,?after?modification?through?c2?=?"?<<?a?<<?'\n';????auto?[v,?w]?=?f<0>();?//?結構化綁定聲明 auto d = {1, 2}; // OK:d 的類型是 std::initializer_list<int> auto n = {5}; // OK:n 的類型是 std::initializer_list<int>// auto e{1, 2}; // C++17 起錯誤,之前為 std::initializer_list<int> auto m{5}; // OK:C++17 起 m 的類型為 int,之前為 initializer_list<int>//? decltype(auto) z =?{ 1, 2 }?//?錯誤:{1, 2}?不是表達式 // auto 常用于無名類型,例如 lambda 表達式的類型 auto lambda = [](int x) { return x + 3; };?//??auto?int?x;?//?于?C++98?合法,C++11?起錯誤// auto x; // 于 C 合法,于 C++ 錯誤}

    可能的輸出:

    a, before modification through c2 = 3a, after modification through c2 = 4

    區別

    auto 和 decltype 關鍵字都可以自動推導出變量的類型,但它們的用法是有區別的:

    auto varname = value;
    decltype(exp) varname = value;

    其中,varname 表示變量名,value 表示賦給變量的值,exp 表示一個表達式。

    auto 根據=右邊的初始值 value 推導出變量的類型,而 decltype 根據 exp 表達式推導出變量的類型,跟=右邊的 value 沒有關系。?

    總結

    以上是生活随笔為你收集整理的decltype 和 auto的全部內容,希望文章能夠幫你解決所遇到的問題。

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