簡體   English   中英

為什么 C++ 標准不更改 std::set 以使用 std::less<> 作為其默認模板參數?

[英]Why does the C++ standard not change std::set to use std::less<> as its default template argument?

#include <set>
#include <string>
#include <string_view>

using namespace std::literals;

int main()
{
    auto v1 = std::set<std::string, std::less<>>{"abc"s};
    v1.contains("abc"s);  // ok
    v1.contains("abc"sv); // ok
    
    auto v2 = std::set{"abc"s};
    v2.contains("abc"s);  // ok
    v2.contains("abc"sv); // error
}

v1.contains("abc"sv); v1.contains("abc"s);更有效 , 因為它不需要構造一個字符串 object。

但是,C++ 標准使用std::less<T>而不是std::less<>作為std::set的默認模板參數。 所以, CTAD(類模板參數推導)std::less<>上不起作用,我必須寫丑陋的std::set<std::string, std::less<>>{"abc"s} ,而不是std::set{"abc"s}

為什么 C++ 標准不更改std::set以使用std::less<>作為其默認模板參數? 只是為了向后兼容?

std::set<T, std::less<T>>移動到std::set<T, std::less<>>可以使關鍵字查找算法更有效,如果搜索關鍵字不必轉換。

相反,如果轉換發生在每次調用比較器時,而不是在調用者啟動算法時發生一次,它可能會降低它們的效率。 這些轉換可能非常昂貴。

特別是如果從 search-key 到T的轉換是有損的,甚至不能保證兩者都會產生相同的結果!

由於這些原因,這樣的改變不是直接的升級,而是突破性的改變。 委員會非常不願意介紹這些。

為什么 C++ 標准不更改std::set以使用std::less<>作為其默認模板參數? 只是為了向后兼容?

這將是 ABI 中斷。

// a.cpp
void f(std::set<int> const&) { ... }

// b.cpp
void g() {
    std::set<int> s = /* ... */;
    f(s);
}

如果a.cpp在 C++11 上編譯,則f采用std::set<int, std::less<int>>

如果標准庫將 C++14 中的默認比較從std::less<T>更改為std::less<void>N3421僅在 2012 年編寫),並且b.cpp在 C++14 上編譯,則s將是std::set<int, std::less<void>> 現在我們無法鏈接。

我的猜測是因為他們認為打破向后兼容性並不是很大的改進。

另一個原因是因為帶有std::less<Key>std::set甚至在 C++11 之前就已經存在(我猜是從 C++03 開始),而std::less<>僅出現在 C++14 中。 因此,如果他們使用std::less<>移動到std::set ,那么您必須在使用 set 時強制 C++14 ,或者您必須制作兩種集合 - 一種用於 C++03,一種用於 C++14。

此外,如果您從 C++14 開始設置基於 std::less<> 的設置,那么您的 C++14 之前的代碼有時會開始表現不同。 例如,您的代碼在添加到 set 時出於某種原因依賴於調用 Key 的構造函數,然后突然如果您添加選項-std=c++14您的舊代碼開始執行其他操作。

通常 STD 人會做出這樣的改變,從 C++11 切換到 C++14 不會破壞代碼的行為。 只有從 C++14 向下切換到 C++11 才能破壞某些東西(通常是非編譯)。 換句話說,使用 std::less<> 是向后兼容的破壞性更改。 此類更改通常僅通過為此類專業化引入新的 class 名稱來完成。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM