为什么 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);
更高效,因为它不需要构造字符串对象。
但是,C++ 标准使用 std::less<T>
而不是 std::less<>
作为 std::set
的默认模板参数。所以,CTAD (Class Template Argument Deduction) 对 std::less<>
不起作用,我必须写丑陋的 std::set<std::string, std::less<>>{"abc"s}
,而不是 [=20] =].
为什么 C++ 标准不更改 std::set
以使用 std::less<>
作为其默认模板参数?只是为了向后兼容?
我的猜测是因为他们认为打破向后兼容性并不是很大的改进。
另一个原因是因为 std::set
和 std::less<Key>
甚至在 C++11 之前就已经存在(我猜是从 C++03 开始),而 std::less<>
只出现在 C++14 中.因此,如果他们使用 std::less<>
移动到 std::set
那么你必须在使用 set 时强制使用 C++14,或者你必须制作两种集合 - 一种用于 C++03,一种用于 C+ +14.
此外,如果您从 C++14 开始,使 set 成为 std::less<>-based,那么您的 C++14 之前的代码有时会开始表现不同。例如,您的代码在添加到集合时出于某种原因依赖于调用 Key 的构造函数,然后如果您添加选项 -std=c++14
,您的旧代码突然开始做其他事情。
通常 STD 人员会做出这样的更改,即从 C++11 切换到 C++14 不会破坏代码的行为。只有从 C++14 向下切换到 C++11 才能破坏某些东西(通常是非编译)。换句话说,使用 std::less<> 是向后兼容性破坏性更改。此类更改通常只能通过为此类专业引入新的 class 名称来完成。
从 std::set<T, std::less<T>>
移动到 std::set<T, std::less<>>
可以使关键字查找算法更有效,如果搜索关键字永远不必转换的话。
相反,如果转换在每次调用比较器时发生,而不是在启动算法时在调用者中发生一次,则可能会降低它们的效率。这些转换可能非常昂贵。
特别是如果从搜索键到 T
的转换是有损的,甚至不能保证两者会产生相同的结果!
出于这些原因,这样的更改不是直接升级,而是重大更改。而且委员会很不愿意介绍这些。
Why does the C++ standard not change std::set
to use std::less<>
as its default template argument? Just for backward compatibility?
这将是 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>>
。而现在我们无法 link.
#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);
更高效,因为它不需要构造字符串对象。
但是,C++ 标准使用 std::less<T>
而不是 std::less<>
作为 std::set
的默认模板参数。所以,CTAD (Class Template Argument Deduction) 对 std::less<>
不起作用,我必须写丑陋的 std::set<std::string, std::less<>>{"abc"s}
,而不是 [=20] =].
为什么 C++ 标准不更改 std::set
以使用 std::less<>
作为其默认模板参数?只是为了向后兼容?
我的猜测是因为他们认为打破向后兼容性并不是很大的改进。
另一个原因是因为 std::set
和 std::less<Key>
甚至在 C++11 之前就已经存在(我猜是从 C++03 开始),而 std::less<>
只出现在 C++14 中.因此,如果他们使用 std::less<>
移动到 std::set
那么你必须在使用 set 时强制使用 C++14,或者你必须制作两种集合 - 一种用于 C++03,一种用于 C+ +14.
此外,如果您从 C++14 开始,使 set 成为 std::less<>-based,那么您的 C++14 之前的代码有时会开始表现不同。例如,您的代码在添加到集合时出于某种原因依赖于调用 Key 的构造函数,然后如果您添加选项 -std=c++14
,您的旧代码突然开始做其他事情。
通常 STD 人员会做出这样的更改,即从 C++11 切换到 C++14 不会破坏代码的行为。只有从 C++14 向下切换到 C++11 才能破坏某些东西(通常是非编译)。换句话说,使用 std::less<> 是向后兼容性破坏性更改。此类更改通常只能通过为此类专业引入新的 class 名称来完成。
从 std::set<T, std::less<T>>
移动到 std::set<T, std::less<>>
可以使关键字查找算法更有效,如果搜索关键字永远不必转换的话。
相反,如果转换在每次调用比较器时发生,而不是在启动算法时在调用者中发生一次,则可能会降低它们的效率。这些转换可能非常昂贵。
特别是如果从搜索键到 T
的转换是有损的,甚至不能保证两者会产生相同的结果!
出于这些原因,这样的更改不是直接升级,而是重大更改。而且委员会很不愿意介绍这些。
Why does the C++ standard not change
std::set
to usestd::less<>
as its default template argument? Just for backward compatibility?
这将是 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>>
。而现在我们无法 link.