How to use comparator with is_transparent type?

with C ++ 14, we are allowed to compare the elements of some associative containers (for example, std :: set) with other types than those stored in the container. It should work when the comparator has is_transparent denoted as type (see, for example, std :: set :: find ).

Suppose I have a string wrapper that performs some string checks (if its format is a valid format, etc. - not very important, but building it is heavy enough that I would like to avoid it), it can throw exceptions) , and it is stored in std :: set to have a container with unique values. How do I write a comparator for this? Should it look like below? Can I overload and use my sw::operator<() to achieve the same?

 class sw { public: explicit sw(const std::string& s) : s_(s) { /* dragons be here */ } const std::string& getString() const { return s_; } bool operator<(const sw& other) const { return s_ < other.s_; } private: std::string s_; }; struct Comparator { using is_transparent = std::true_type; bool operator()(const sw& lhs, const std::string& rhs) const { return lhs.getString() < rhs; } bool operator()(const std::string& lhs, const sw& rhs) const { return lhs < rhs.getString(); } bool operator()(const sw& lhs, const sw& rhs) const { return lhs < rhs; } }; int main() { std::set<sw, Comparator> swSet{ sw{"A"}, sw{"B"}, sw{"C"} }; std::cout << std::boolalpha << (swSet.find(std::string("A")) != swSet.end()) << std::endl; } 

I believe that the above code should work as expected, but when I tested it with g ++ 4.9 and clang ++ 3.6, both gave errors regarding the lack of conversion from string to key_type , as if the lines overloaded Comparator::operator() never were taken into account. Did I miss something?

+7
c ++ c ++ 14 stdset
source share
1 answer

Yes, this code is correct, but it would be easier to overload operator< so that you can compare your type with std::string , and then just use std::less<> (i.e. std::less<void> ), which is already transparent.

 inline bool operator<(const sw& lhs, const std::string& rhs) { return lhs.getString() < rhs; } inline bool operator<(const std::string& lhs, const sw& rhs) { return lhs < rhs.getString(); } std::set<sw, std::less<>> swSet{ sw{"A"}, sw{"B"}, sw{"C"} }; 

In addition, it may be worth noting that it does not matter that you define is_transparent to, any of them will have the same effect as its definition:

 using is_transparent = std::false_type; using is_transparent = void; 
+3
source share

All Articles