#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);
is more efficient than v1.contains("abc"s);
, because it needn't to construct a string object.
However, the C++ standard uses std::less<T>
, rather than std::less<>
, as std::set
's default template argument. So, CTAD (Class Template Argument Deduction) doesn't work on std::less<>
, I have to write ugly std::set<std::string, std::less<>>{"abc"s}
, rather than std::set{"abc"s}
.
Why does the C++ standard not change std::set
to use std::less<>
as its default template argument? Just for backward compatibility?
My guess is because they thought it wasn't so great improvement to break backward compatibility.
Another reason is because std::set
with std::less<Key>
existed even before C++11 (starting from C++03 I guess) and std::less<>
appeared only in C++14. So if they move to std::set
with std::less<>
then you have to force C++14 when using set, or you have to make two kinds of sets - one for C++03 and one for C++14.
Also if you start from C++14 making set being std::less<>-based then your pre-C++14 code will start to behave differently sometimes. For example your code relied on calling Key's constructor for some reason when adding to set, then suddenly if you add option -std=c++14
your old code starts doing other things.
Usually STD people make such changes that switching from C++11 to C++14 doesn't break code's behaviour. Only downswitching from C++14 to C++11 can break something(usually non-compiling). In other words it is backward compatibility breaking change to use std::less<>. Such changes are usually only done by introducing new class name for such specializations.