C++作為一門靜態類型語言,是需要程式員聲明變數類型的。然而來到了C++11,auto的誕生使得變數聲明變得及為方便,尤其是對於比較長的模板類型,auto一定程度上為代碼編寫者減輕了負擔。到了C++23,突然來了個新特性:auto{x}/auto(x),這又是個什麼東西,它的motivation又是 ...
C++作為一門靜態類型語言,是需要程式員聲明變數類型的。然而來到了C++11,auto的誕生使得變數聲明變得及為方便,尤其是對於比較長的模板類型,auto一定程度上為代碼編寫者減輕了負擔。到了C++23,突然來了個新特性:auto{x}/auto(x),這又是個什麼東西,它的motivation又是什麼?
首先這是一個中國小伙為C++23作出的貢獻,他是一位在美國工作的engineering,這是他的主頁。
到底解決了什麼問題?
來看看這個函數。
void my_erase(auto& x) {
std::erase(x, x.front());
}
假如我們傳入一個vector類型,vector初始化為{1, 2, 3, 1, 2, 3},然後通過調用std::erase,按照正常想法,函數執行完畢之後vector應該僅僅刪掉大小為1首元素。可是事實卻並非如此,通過代碼運行會發現容器剩下的元素是{2, 3, 1, 3},這裡面究竟發生了什麼。
_GLIBCXX_NODISCARD _GLIBCXX20_CONSTEXPR
reference
front() _GLIBCXX_NOEXCEPT
{
__glibcxx_requires_nonempty();
return *begin();
}
通過源碼查看,可以發現front()其實是引用類型,而std::erase本身又調用了std::__remove_if,這也不難讓人想出解決問題的辦法,也就是做一份拷貝。
void my_erase(auto& x) {
auto tmp = x.front();
std::erase(x, tmp);
}
但是既然都來寫Cpp了,我們還可以追求點“潔癖”,我們很多時候並不希望有多餘的拷貝,這時候右值就派上了用場。
void my_erase(auto& x) {
using T = std::decay_t<decltype(x.front())>;
std::erase(x, T{x.front()});
}
在進行”類型萃取“之後,我們就可以獲取到了容器第一個元素的原始類型,或者叫退化類型,即可以去掉cv限定符還有引用的類型(如果傳入的是數組,就會退化為指針)。
但是到了C++23,在上面這種語境的情況下,auto{x}/auto(x)便可大展拳腳,沒再必要進行”類型萃取“。
void my_erase(auto& x) {
std::erase(x, auto{x.front()});
}
最後
在現代C++中,auto無疑是寵兒,從C++11到C++14,再到如今的C++23,它隨時在發展著,使我們的代碼變得更加的簡潔和高效。在上面這個例子當中,我們無需進行多餘的操作,就能大大地簡化代碼,或許將來它還能在更多場合發展出優勢。