这个 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_set
和unordered_map
;给它一些,看看什么更适合您的需求。
您正在用一些值初始化一个集合。这些值恰好来自您的地图,但采购它们并不重要。重要的是集合的构造函数将被赋予以下值以用于工作(这些实际上是 std::pair
s,但大括号符号很方便):
{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.
我无法理解 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_set
和unordered_map
;给它一些,看看什么更适合您的需求。
您正在用一些值初始化一个集合。这些值恰好来自您的地图,但采购它们并不重要。重要的是集合的构造函数将被赋予以下值以用于工作(这些实际上是 std::pair
s,但大括号符号很方便):
{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.