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

C++ 这个std::set初始化是如何工作的?,c++,stdset,C++,Stdset,我在理解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>

我在理解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);
std::map my\u map={
{16, 24},
{19, 29},
{15, 23},
{14, 22},
{13, 21},   
{17, 28},
};
typedef std::函数compareffunction;
比较函数比较=
[](标准::对a,标准::对b){
if(小于(a,b))

std::cout我想让你困惑的是映射迭代器的行为。在映射上迭代(从
my\u map.begin()
my\u map.end()
)意味着遍历类型为
std::pair
(对于键类型
K
和映射值类型
V
);在您的例子中,它是std::pair
。所以实际上,映射非常类似于这些对的集合

现在,您正在使用的集合的构造函数,如@AlgirdasPreidžius和@IgorTandetnik suggest,是集合中的(=从开始迭代器到结束迭代器),因此您得到了一组对

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

现在有意义了吗


PS 1:您可能更喜欢
unordered\u set
unordered\u map
;尝试一下,看看什么更适合您的需要。

您正在用一些值初始化一个集合。这些值恰好来自于您的映射,但寻找它们并不重要。重要的是将给出集合的构造函数使用以下值(这些值实际上是
std::pair
s,但大括号表示法很方便):

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

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

不过,第二个元素需要放在集合中维护顺序的位置。也就是说,构造函数需要知道新元素(
{14,22}
)的比较是否小于现有元素(
{13,21}
)。它是如何发现的?它调用您给它的函数:
比较({14,22},{13,21})
。返回true,因此新元素在集合中位于旧元素之前。
注意:参数的顺序不是固定的;因为输出是“b”,我猜这就是使用的顺序

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

剩下的三个元素也是如此

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


实际上,构造函数可能会被总是返回true的函数所迷惑。最好让它返回a是否被认为小于b。

您是否尝试过查看文档中可能的构造函数?我不确定我是否完全理解您困惑的本质。您正在使用谢谢,我意识到它使用了范围构造函数,但我看不到映射的迭代器如何自动与lambda函数一起工作。什么是“魔法”当我初始化集合时,在它后面?
std::set
将其元素按顺序排序。为了做到这一点,它需要对它们进行比较。因此调用比较函数。否则为什么您认为您提供了一个比较函数?如果从未调用它,它不是毫无意义吗?您的比较函数总是返回
true
,这是意味着
集合
在尝试使用比较器时会感到困惑。您应该返回
lessthan
的结果(假设这是一个有效的比较函数,如
a
std::less
),为了更好地调试,您可能还希望打印出对的实际值,而不仅仅是
“a”
“b”
。非常感谢您,这确实帮助我们澄清了问题,非常感谢
{13,21}  {14,22}  {15,23}  {16,24}  {17,28}  {19,29}