在前面兩篇部落格:
c++ 中的左值與右值
c++ 中的 std::move 與 std::forward
對c++ 中的萬能引用及std::forward有了一定的了解,這裡主要是要說明當函式使用萬能引用時就要小心再使用函式過載了,不然稍不留神就會出現我們意想不到的錯誤。
std::multiset names;
template
<
typename t>
void
logandadd
(t&& name)
std::string petname
("jane");
logandadd
(petname)
;// 傳遞左值,使用複製
logandadd
(std::
string
("kangkang"))
;// 傳遞右值,使用移動語義
logandadd
("pet");
// names 會直接構造乙個 string 物件,而不是複製
上述使用萬能模板+ std::forward 可以到達我們對效率的追求,這時需要有一點點變化,我們的 name 存在乙個容器中,需要乙個 index 才能獲得。
// 獲取 name 的函式
std::string getname
(int index)
;void
logandadd
(int idx)
logandadd(2
);// 呼叫 int 的過載版本
當輸入的 idx 需要隱式轉換時就可能會存在問題:
short idx =2;
logandadd
(idx)
;// 會發生編譯錯誤!!
原因是萬能模板匹配可以把 t 推導為 short,屬於精確匹配,short 則需要隱式變換成 int後才可以匹配,精確匹配的優先順序更高,這時候實際編譯器會匹配到萬能引用版本的函式,這是時候就會用乙個 short 型別的值去初始化乙個 string 型別,就會發生錯誤!
class
person
// 萬能引用建構函式
explicit
person
(int idx)
:name
(getname
(idx)
)// 過載的建構函式
『』『person
(const person& rhs)
;// 編譯器自動生成的複製建構函式
person
(person&& rhs)
;// 編譯器自動生成的移動建構函式
』『』..
.private
: std::string name;
}
在類中對建構函式進行了過載,當我們使用這個類時可能遇到下面的問題:
person p
("nancy");
auto
clone_p
(p);// 這步就無法完成編譯
無法正常呼叫複製建構函式的原因是這裡的萬能匹配模板可以把 t 推導成 person 型別的,是乙個非常量左值引數,也是精準匹配,而複製建構函式接受的是常量左值引數,需要將傳入的 p 加上 const 屬性才能呼叫,所以優先呼叫了萬能模板的建構函式,用 person 型別類初始化乙個 string 型別。
想要使用建構函式則可以進行如下操作:
const person cp
("nancy");
auto
clone_cp
(cp)
;// 這樣就可以呼叫複製建構函式了
上述不加 const 的版本無法呼叫複製建構函式,同理 person 的繼承類也會有更多問題。
class
specialperson
:public person
// 子類移動構造,還是會呼叫父類萬能引用構造
specialperson
(speicalperson&& rhs)
:person
(std::
move
(rhs)
)}
所以盡可能避免過載使用萬能引用的函式。 C 日記 Day59 萬能引用
templatevoid func t tmpv 萬能引用 既能接受右值,又能接受左值 滿足以下條件,右值引用會變為萬能引用 a 必須是函式模板 b 必須是發生了模板型別推斷並且函式模板形參的樣子是 t auto也存在萬能引用,以後再說。萬能引用 和 右值引用 的區別 1 右值引用得傳遞右值,否則編...
萬能的函式(三)
形成閉包的條件 在之前的文章中看到過這樣描述裝飾器的話,很形象。先來個簡單的裝飾器 上面的例子傳入的是無引數的函式。如果我們想要傳入帶引數的函式怎麼辦?defadd a b return a b print a b deffn print hello world def demo def new f...
C 萬能標頭檔案
萬能標頭檔案其實就一行 include其實它包括了 基本包括了大部分的stl庫函式,使用方便快捷 include include include include include include include 向量 include 佇列 include include include include...