这个 std::set 初始化是如何工作的?

How does this std::set initialization work?

我无法理解 std::set 初始化的工作原理。我在函数中有以下代码:

std::map<int, int> my_map  = {
    {16, 24},
    {19, 29},
    {15, 23},
    {14, 22},
    {13, 21},   
    {17, 28},
};

typedef std::function<bool(std::pair<int, int>, std::pair<int, int>)> comparefunction;


comparefunction compare = 
    [](std::pair<int, int> a, std::pair<int, int> b){
        if(lessthan(a,b))
            std::cout << "a" << std::endl;
        else
            std::cout << "b" << std::endl;


        return true;
    };

std::set<std::pair<int, int>, comparefunction>
    values(my_map.begin(), my_map.end(), compare);

调用这个函数的时候打印了几次"b",怎么回事?

编辑: 我意识到我使用了范围构造函数,但它 "automatically" 如何使用地图中的元素调用 lambda 函数?我似乎无法在文档中找到它。打印a和b的内容总是一样的,这是为什么呢?

我认为让您感到困惑的是地图迭代器的行为方式。遍历映射(从 my_map.begin()my_map.end())意味着遍历对,其类型为 std::pair<K, V>(对于键类型 K 和映射值类型 V) ;在你的例子中是 std::pair<int, int>。所以实际上,地图很像这些对的集合。

现在,您正在使用的集合的构造函数,如@AlgirdasPreidžius 和@IgorTandetnik 建议的那样,是集合中的 constructor which inserts all of the elements in some range(= 从开始迭代器到结束迭代器)。所以你得到一组对。

最后,lambda 出现可能会改变元素相同的规则。

现在有意义吗?

PS 1:您可能更喜欢unordered_setunordered_map;给它一些,看看什么更适合您的需求。

您正在用一些值初始化一个集合。这些值恰好来自您的地图,但采购它们并不重要。重要的是集合的构造函数将被赋予以下值以用于工作(这些实际上是 std::pairs,但大括号符号很方便):

{13,21}  {14,22}  {15,23}  {16,24}  {17,28}  {19,29}

[在这一点上,有人可能会注意到,我不是按照地图初始化的顺序,而是按照它们的第一个坐标(地图的键)来排序。这是因为map是有序的,所以begin()end()遍历map从key最低到最高。]

那会发生什么?集合的构造函数创建一个集合,然后将这些元素添加到其中。第一个元素({13,21})没问题;向空集合中添加元素很容易。

不过,第二个元素需要放在集合中保持顺序的位置。也就是说,构造函数需要知道新元素 ({14, 22}) 是否小于现有元素 ({13,21})。它是如何发现的?它调用你给它的函数:compare({14, 22}, {13,21})。这 return 是正确的,因此新元素在集合中位于旧元素之前。
注意:参数顺序不固定;由于输出是 "b",我猜这是使用的顺序。

添加第三个元素({15,23})类似。构造函数需要知道它在集合中的位置,因此它从现有元素之一开始(实现者选择我们从哪里开始)并使用该元素和新元素调用您的函数。您的函数 return 为真,因此新元素将放置在现有元素之前。根据选择的元素,可能需要再次调用 compare 以确定新元素在集合中排在第一位。
注意:如果实现者选择了其他顺序的参数,则新元素将排在集合的最后;如果发生这种情况,您大概会看到 "a"s 而不是 "b"s。

其余三个元素依此类推

想混淆构造函数吗?让你的 lambda return 为 false 而不是 true。这将使构造函数相信所有对都是等价的,这意味着在用六个元素构造之后,该集合将只包含一个({13,21})。在这种情况下,将 "set" 更改为 "multiset" 将允许添加其他元素。

实际上,构造函数可能会被始终 return 为真的函数所混淆。最好有它 return 无论 a 是否被认为小于 b.