[英]C++ overriding default less than argument for std::set for a particular data type
[英]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.