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

Following code works well without issues but wondering, if it is possible to rewrite custom comparison operator using boost::iequals , which compares without converting to 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;


Solution 1:[1]

I would define a comparator like this:

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

Then you can use it with your datastructure of choice:

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

Prints

---
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

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 sehe