c++ - 为什么 std::flat_set 和 std::flat_map 具有 std::initializer_list 的重载构造函数,而其他容器适配器则没有?

标签 c++ stl initializer-list c++23 stdstack

我注意到 C++23 为 std::stackstd::queue 容器适配器的构造函数添加了新的重载,允许构造底层容器包含 [first, last) 范围内的内容。 cppreference 还展示了如何将这些重载与 std::initializer_list 一起使用,并提供以下示例:

const auto il = {2, 7, 1, 8, 2};
std::stack<int> c4 { il.begin(), il.end() }; // overloads (6), C++23

const auto il = {2, 7, 1, 8, 2};
std::queue<int> c4 { il.begin(), il.end() }; // overload (6), C++23

这意味着不需要引入其他重载构造函数来使用 std::initialization_list 的内容构造底层容器。 然而,C++23还添加了其他容器适配器,例如std::flat_set,cppreference显示了std::flat_set容器适配器的实现示例,其中提供了以下重载构造函数:

flat_set(initializer_list<key_type> il, const key_compare& comp = key_compare())
 : flat_set(il.begin(), il.end(), comp) { }

template<class Allocator>
flat_set(initializer_list<key_type> il, const key_compare& comp, const Allocator& a);

template<class Allocator>
flat_set(initializer_list<key_type> il, const Allocator& a);

为什么 std::flat_setstd::flat_map 具有 std::initializer_list 的重载构造函数,而其他容器适配器却没有?

最佳答案

我将在这里复制我的标准提案答案,因为它涵盖的内容比上面 LoS 自己的答案要多一些。

首先引用P2447R3 :

Yes, any change to overload sets (particularly the addition of new non-explicit constructors) can break code. But that's not necessarily a proposal-killer. For example, there was nothing wrong with C++23’s adopting [P1425] "Iterator-pair constructors for stack and queue" with no change to Annex C, despite its breaking code like this:

void zero(queue<int>);
void zero(pair<int*,int*>);
int a[10];
void test() { zero({a, a+10}); }

Before: Calls zero(pair<int, int>).
After P1425: Ambiguous.
To fix: Eliminate the ambiguous overloading, or cast the argument to pair.

We can simply agree that such examples are sufficiently unlikely in practice, and sufficiently easy to fix, that the benefits of the changed overload set outweigh the costs of running into these examples.

然后我写道:

I think priority_queue should get an initializer_list ctor, because we all know what priority_queue<int> pq = {1,2,3} ought to do. I think queue probably should get an initializer_list ctor, because I assume we all know what queue<int> q = {1,2,3} ought to do: items pop from the front of the queue, so "1" would be at the front, right? I'm more skeptical of stack. I don't think anyone would guess better than 50/50 what stack<int> st = {1,2,3} ought to do, as written. Items pop from the "top" of a stack, yes, but is that the left end or the right end? (Experts know it must be the right end because that's the only efficient end when the container is a vector; but I don't think that's terribly obvious.) However, on the other hand, it's true that the iterator-pair ctor Does The Right Thing: if you push 1, then 2, then 3, you end up with an underlying vector containing {1,2,3}. So why not just let the programmer write {1,2,3} in the first place? So I'm skeptical, but not completely anti.

Anyway, in all of those cases, adding new ctors will change overload sets — and change them drastically, because initializer_list ctors are even greedier than other non-explicit ctors. (This is why implicit conversions are the devil, and the STL's prevailing style of "make everything implicit unless there's a positive reason to make it explicit" is the Wrong Default as usual. Python got it right.) So that's probably why LEWG has been leery of doing so.

OTOH, flat_set and flat_map are completely novel class types; nobody has any existing code that would be broken by fiddling with their overload sets. And flat_set is supposed to be a drop-in replacement for set! So obviously it would be a non-starter if you could write

std::set<int> s = {1,2,3};

but not

std::flat_set<int> s = {1,2,3};

That just has to work, period.

关于c++ - 为什么 std::flat_set 和 std::flat_map 具有 std::initializer_list 的重载构造函数,而其他容器适配器则没有?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/75678325/

相关文章:

c++ - 传递数组作为引用

arrays - 如何将数组传递给 std::make_tuple?

c++ - c++11 中 std::initializer_list 的好处

c++ - 错误 : 'e' is not a class, 命名空间或枚举

c - C 的 std::unordered_set(int) 容器库

c++ - 初始化器列表和运算符的 RHS

c++ - 为来自不同进程的窗口设置父级是否正确?

c++ - 使用 C++ 在 Linux 中设置系统和硬件时间

c++ - 将 CVD 图像转换为彩色 OpenCV 图像

c++ - 在 C++ 中使用命名空间时出现 "does not name a type"错误