auto:
就是編譯器能夠根據表示式的型別,自動決定變數的型別(從 c++14 開始,還有函式的返回型別),不再需要程式設計師手工宣告([1])。但需要說明的是,auto 並沒有改變 c++ 是靜態型別語言這一事實——使用 auto 的變數(或函式返回值)的型別仍然是編譯時就確定了,只不過編譯器能自動幫你填充而已。
例1:容器迭代器型別:
// vectorv;
for(vector<
int>
::iterator
it = v.
begin()
, end = v.
end();
it != end;
++it)
for
(auto it = v.
begin()
, end = v.
end();
it != end;
++it)
例2:未知型別:
不使用自動型別推斷時,如果容器型別未知的話,我們還需要加上 typename(注意此處 const 引用還要求我們寫 const_iterator 作為迭代器的型別):
template
<
typename t>
void
foo(
const t& container)
如果 begin 返回的型別不是該型別的 const_iterator 巢狀型別的話,那實際上不用自動型別推斷就沒法表達了。這還真不是假設。比如,如果我們的遍歷函式要求支援 c 陣列的話,不用自動型別推斷的話,就只能使用兩個不同的過載:
template
<
typename t, std::size_t n>
void
foo(
const t (
&a)[n])}
template
<
typename t>
void
foo(
const t& c)
}
如果使用自動型別推斷的話,再加上 c++11 提供的全域性 begin 和 end 函式,上面的**可以統一成:
template
<
typename t>
void
foo(
const t& c)
}
自動型別推導的優點:
自動型別推斷不僅降低了**的囉嗦程度,也提高了**的抽象性,使我們可以用更少的**寫出通用的功能。
auto的實際使用規則類似於函式模板引數的推導規則:
1. auto a = expr; 意味著用 expr 去匹配乙個假想的 template f(t) 函式模板,結果為值型別。
2. const auto& a = expr; 意味著用 expr 去匹配乙個假想的 template f(const t&) 函式模板,結果為常左值引用型別。
3. auto&& a = expr; 意味著用 expr 去匹配乙個假想的 template f(t&&) 函式模板,結果是乙個跟 expr 值類別相同的引用型別。
decltype:
decltype 的用途是獲得乙個表示式的型別,結果可以跟型別一樣使用。它有兩個基本用法:
1. decltype(變數名) 可以獲得變數的精確型別。
2. decltype(表示式) (表示式不是變數名,但包括 decltype((變數名)) 的情況)可以獲得表示式的引用型別;除非表示式的結果是個純右值(prvalue),此時結果仍然是值型別。
如果我們有 int a;,那麼:
* decltype(a) 會獲得 int(因為 a 是 int)。
* decltype((a)) 會獲得 int&(因為 a 是 lvalue)。
* decltype(a + a) 會獲得 int(因為 a + a 是 prvalue)。
通常情況下,能寫 auto 來宣告變數肯定是件比較輕鬆的事。但這兒有個限制,你需要在寫下 auto 時就決定你寫下的是個引用型別還是值型別。根據型別推導規則,auto 是值型別,auto& 是左值引用型別,auto&& 是**引用(可以是左值引用,也可以是右值引用)。使用 auto 不能通用地根據表示式型別來決定返回值的型別。不過,decltype(expr) 既可以是值型別,也可以是引用型別。因此,我們可以這麼寫:
c++14 引入了 decltype(auto) 語法:
decltype
(auto
) a = expr;
這種**主要用在通用的**函式模板中:你可能根本不知道你呼叫的函式是不是會返回乙個引用。這時使用這種語法就會方便很多。
類模板的模板引數推導:
如果你用過 pair 的話,一般都不會使用下面這種形式:
pair<
int,
int> pr
;
auto pr =
make_pair(1
,42);
在進入了 c++17 的世界後,這類函式變得不必要了。現在我們可以直接寫:
pair pr
;
array自動型別推導:
int a1=
;array<
int,
3> a2
;// 囉嗦
// arraya3; 不行
c++17:
array a
;// 得到 array
結構化繫結:
c++17前:
multimapint>
::iterator lower, upper;
std::
tie(lower, upper)
= mmp.
equal_range
("four"
);
c++17後:
auto
[lower, upper]
= mmp.
equal_range
("four"
);
c98:
vector<
int> v;
v.push(1
);v.push(2
);v.push(3
);v.push(4
);v.push(5
);
c++11:
vector<
int> v
;
統一初始化:
在**裡使用了大括號 {} 來進行物件的初始化。這當然也是 c++11 引入的新語法,能夠代替很多小括號 () 在變數初始化時使用。這被稱為統一初始化(uniform initialization)。
如果乙個類既有使用初始化列表的建構函式,又有不使用初始化列表的建構函式,那編譯器會千方百計地試圖呼叫使用初始化列表的建構函式,導致各種意外。所以,如果給乙個推薦的話,那就是:
* 如果乙個類沒有使用初始化列表的建構函式時,初始化該類物件可全部使用統一初始化語法。
* 如果乙個類有使用初始化列表的建構函式時,則只應用在初始化列表構造的情況。
類資料成員的預設初始化
按照 c++98 的語法,資料成員可以在建構函式裡進行初始化。這本身不是問題,但實踐中,如果資料成員比較多、建構函式又有多個的話,逐個去初始化是個累贅,並且很容易在增加資料成員時漏掉在某個建構函式中進行初始化。為此,c++11 增加了乙個語法,允許在宣告資料成員時直接給予乙個初始化表示式。這樣,當且僅當建構函式的初始化列表中不包含該資料成員時,這個資料成員就會自動使用初始化表示式進行初始化。
class
complex
complex
(float re)
:re_
(re)
,im_(0
)complex
(float re,
float im)
:re_
(re)
,im_
(im)
…private
:float re_;
float im_;
};
假設由於某種原因,我們不能使用預設引數來簡化建構函式,我們可以用什麼方式來優化上面這個**呢?使用資料成員的
預設初始化的話,我們就可以這麼寫:
class
complex
complex
(float re)
:re_
(re)
complex
(float re,
float im)
:re_
(re)
,im_
(im)
private
:float re_
;float im_;}
;
第乙個建構函式沒有任何初始化列表,所以類資料成員的初始化全部由預設初始化完成,re_ 和 im_ 都是 0。第二個建構函式提供了 re_ 的初始化,im_ 仍由預設初始化完成。第三個建構函式則完全不使用預設初始化。 C 11新特性之新型別與初始化
這是c 11新特性介紹,雖然現在來說有些不合時宜,但是也有一些有趣的地方。覺得麻煩的可以直接跳到最後哦!long long型別 c 11標準中新加入了long long型別屬性,占用空間不小於long型別。測試 如下 long large long max long long long large ...
C 11新特性 自動型別推斷和型別獲取
當編譯器能夠在乙個變數的宣告時候就推斷出它的型別,那麼你就能夠用auto關鍵字來作為他們的型別 cpp view plain copy auto x 1 編譯器當然知道x是integer型別的。所以你就不用int了。接觸過泛型程式設計或者api程式設計的人大概可以猜出自動型別推斷是做什麼用的了 幫你...
C 3 0新特性之物件初始化器
物件初始化器用於指定物件的乙個或多個可訪問的字段或屬性的值,通過 進行封閉起來,多個字段賦值之間通過逗號分割。具體語法元素是 1.物件建立表示式 new 型別 型別引數 可選 物件或集合初始化器可選 new 型別物件或集合初始化器 2.物件或集合初始化器 物件初始化器 集合初始化器 3.物件初始化器...