Created
April 19, 2022 20:35
-
-
Save jwpeterson/b8e39b04b2cb9a00903d7e29d490144e to your computer and use it in GitHub Desktop.
Demonstration of C++14 is_transparent comparison object with std::set
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <set> | |
#include <memory> | |
#include <iostream> | |
template <typename Container> | |
void print_address(const Container & c) | |
{ | |
std::cout << "address of underlying" << std::endl; | |
for (const auto & ptr : c) | |
std::cout << ptr.get() << std::endl; | |
} | |
template <typename Container> | |
void print_value(const Container & c) | |
{ | |
std::cout << "dereference underlying" << std::endl; | |
for (const auto & ptr : c) | |
std::cout << *ptr << std::endl; | |
} | |
// Struct which defines a custom comparison object that | |
// can be used with std::sets of std::unique_ptrs | |
template <class T> | |
struct CompareUnderlying | |
{ | |
// As of C++14, std::set::find can be a templated overload. | |
// https://en.cppreference.com/w/cpp/container/set/find | |
// We enable this by defining is_transparent as a type. | |
using is_transparent = void; | |
// This is already what the default operator< comparison for std::unique_ptrs does, | |
// we are not adding anything here. | |
bool operator()(const std::unique_ptr<T> & a, const std::unique_ptr<T> & b) const | |
{ | |
return a.get() < b.get(); | |
} | |
// operator< comparison when rhs is a dumb pointer | |
bool operator()(const std::unique_ptr<T> & a, const T * const & b) const | |
{ | |
return a.get() < b; | |
} | |
// operator< comparison when lhs is a dumb pointer | |
bool operator()(const T * const & a, const std::unique_ptr<T> & b) const | |
{ | |
return a < b.get(); | |
} | |
}; | |
int main() | |
{ | |
{ | |
std::set<std::unique_ptr<int>> s; | |
s.insert(std::make_unique<int>(1)); | |
s.insert(std::make_unique<int>(2)); | |
s.insert(std::make_unique<int>(3)); | |
s.insert(std::make_unique<int>(3)); // Not a duplicate. A separate pointer-to-int whose value also happens to be 3 | |
std::cout << "s1" << std::endl; | |
print_address(s); | |
print_value(s); | |
} | |
{ | |
// A set that uses so-called heterogeneous comparisons | |
std::set<std::unique_ptr<int>, std::less<>> s2; | |
s2.insert(std::make_unique<int>(1)); | |
s2.insert(std::make_unique<int>(2)); | |
s2.insert(std::make_unique<int>(3)); | |
s2.insert(std::make_unique<int>(3)); // Still not a duplicate | |
std::cout << "s2" << std::endl; | |
print_address(s2); | |
print_value(s2); | |
// Search for entry by address of underlying | |
// int * first = s2.begin()->get(); | |
// auto result = s2.find(first); // error: no match for 'operator<' (operand types are 'const std::unique_ptr<int>' and 'int* const') | |
} | |
{ | |
std::set<std::unique_ptr<int>, CompareUnderlying<int>> s3; | |
s3.insert(std::make_unique<int>(1)); | |
s3.insert(std::make_unique<int>(2)); | |
s3.insert(std::make_unique<int>(3)); | |
s3.insert(std::make_unique<int>(3)); // Still not a duplicate, does pointer comparisons not value comparisons | |
std::cout << "s3" << std::endl; | |
print_address(s3); | |
print_value(s3); | |
// Search for entry by address of underlying | |
int * first = s3.begin()->get(); | |
auto result = s3.find(first); | |
if (result != s3.end()) | |
std::cout << "Underlying pointer found!" << std::endl; | |
} | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment