简体   繁体   中英

Duplicates when inserting into std::set<std::tuple<std::string, …>>

I tried to use std::tuple as an element of std::set where std tuple consists of std::string and a bool (for this example only, in normal use case the tuple consists of 3 elements). The string of the tuple shall be unique, therefore I created comparator that would sort the elements on the first element of the tuple. However, when inserting into aforementioned set I do get duplicate elements in the container. I cannot see where I am making a mistake. Thanks in advance for suggestions!

#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;
}

Debugger snippet

Output:
ahoy
duplicates
creates
this
ahoy

std::string::compare returns int (neg, 0, positive) not bool (less than),

you want

std::get<0>(l).compare(std::get<0>(r)) < 0;

or

std::get<0>(l) < std::get<0>(r);

a.compare(b) returns:

0          when the strings are equal
negative   when a comes before b  (ie a < b)
positive   when b comes before a  (ie b < a)

However, the comparators return value is converted to a bool and anything but 0 is converted to true , hence your comparator considers a < b to be true for any a and b unless a == b . In particular a < b is true and b < a is considered as true as well. This is not in accordance with the requirement of a strict weak ordering and causes undefined behavior. You can use the "normal" < to compare the strings.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM