std::set 使用 boost::iequals 自定义字符串比较

std::set custom string comparison using boost::iequals

以下代码运行良好,没有问题,但想知道是否可以使用 boost::iequals 重写自定义比较运算符,该运算符在不转换为 upper.

的情况下进行比较
std::string copyToUpper(std::string s)
{
    std::transform(s.begin(),s.end(),s.begin(),::toupper);
    return s;   
}

struct caseInsensitiveCompare {
    bool operator() (const std::string& a, const std::string& b) const {
        return (copyToUpper(a).compare(copyToUpper(b)) < 0);
    }
};
std::set<std::string, caseInsensitiveCompare> keys;

几乎所有 STL 容器都依赖于 strict weak ordering. So the comparison function needs to return, not whether the strings are equal to each other, but that one is "less" than the other. But boost::iequals 检查相等性,而不是检查一个字符串是否“小于”另一个字符串,因此您不能将它用于映射、集合或集合的比较器排序功能。

我会这样定义比较器:

#include <boost/algorithm/string/predicate.hpp>

struct ci_compare {
    bool operator()(std::string_view const& a,
                    std::string_view const& b) const {
        return boost::ilexicographical_compare(a, b);
    }
};

然后您可以将它与您选择的数据结构一起使用:

std::set<std::string, ci_compare> keys;

Live On Compiler Explorer

#include <boost/algorithm/string/predicate.hpp>

struct ci_compare {
    bool operator()(std::string_view const& a,
                    std::string_view const& b) const {
        return boost::ilexicographical_compare(a, b);
    }
};

#include <boost/core/demangle.hpp>
#include <fmt/ranges.h>
#include <map>
#include <set>
using namespace std::string_literals;

auto dump(auto const& data) {
    fmt::print("---\nData structure: {}\nData: {}\nContains 'three'? {}\n",
            boost::core::demangle(typeid(data).name()), data,
            data.contains("three"));
}

int main() {
    dump(std::set{{"hellO", "hEllo", "world"}, ci_compare{}});

    dump(std::map<std::string, int, ci_compare>{
        std::pair{"one"s, 1}, {"TWO"s, 2}, {"Three", 3}});
}

版画

---
Data structure: std::set<char const*, ci_compare, std::allocator<char const*> >
Data: {"hellO", "world"}
Contains 'three'? false
---
Data structure: std::map<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, int, ci_compare, std::allocator<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const, int> > >
Data: {("one", 1), ("Three", 3), ("TWO", 2)}
Contains 'three'? true