问题描述
我尝试使用 std::tuple 作为 std::set 的元素,其中 std 元组由 std::string 和一个 bool 组成(仅在此示例中,在正常用例中,元组由 3 个元素组成)。元组的字符串应该是唯一的,因此我创建了比较器来对元组的第一个元素上的元素进行排序。但是,当插入到上述集合中时,我确实在容器中得到了重复的元素。我看不出我哪里出错了。提前感谢您的建议!
#include <set>
#include <functional>
#include <iostream>
using namespace std;
int main() {
using tuple_t = std::tuple<std::string,bool>;
std::function<bool(const tuple_t &,const tuple_t &)> tupleCmp =
[](const tuple_t & l,const tuple_t & r) -> bool {
return static_cast<bool>(std::get<0>(l).compare(std::get<0>(r)));
};
set<tuple_t,decltype(tupleCmp)> s(tupleCmp);
s.insert(make_tuple("ahoy",false));
s.insert(make_tuple("this",false));
s.insert(make_tuple("creates",false));
s.insert(make_tuple("duplicates",false));
s.insert(make_tuple("ahoy",false));
for (const auto & i : s){
cout << get<0>(i) << endl;
}
auto debug_stop = 0;
}
Output:
ahoy
duplicates
creates
this
ahoy
解决方法
std::string::compare
返回 int
(负,0,正)而不是 bool
(小于),
你想要
std::get<0>(l).compare(std::get<0>(r)) < 0;
或
std::get<0>(l) < std::get<0>(r);
,
a.compare(b)
返回:
0 when the strings are equal
negative when a comes before b (ie a < b)
positive when b comes before a (ie b < a)
但是,比较器的返回值被转换为 bool
,除 0
之外的任何值都被转换为 true
,因此您的比较器认为 a < b
为 {{1} } 对于任何 true
和 a
,除非 b
。特别是 a == b
是 a < b
,true
也被视为 b < a
。这不符合 strict weak ordering 的要求并导致未定义的行为。您可以使用“普通”true
来比较字符串。