auto{x}與auto(x)---一位中國小夥為cppreference作出的貢獻

ChebyshevTST發表於2023-12-28

  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,它隨時在發展著,使我們的程式碼變得更加的簡潔和高效。在上面這個例子當中,我們無需進行多餘的操作,就能大大地簡化程式碼,或許將來它還能在更多場合發展出優勢。

相關文章