Skip to content

Instantly share code, notes, and snippets.

@jwpeterson
Created April 19, 2022 20:35
Show Gist options
  • Save jwpeterson/b8e39b04b2cb9a00903d7e29d490144e to your computer and use it in GitHub Desktop.
Save jwpeterson/b8e39b04b2cb9a00903d7e29d490144e to your computer and use it in GitHub Desktop.
Demonstration of C++14 is_transparent comparison object with std::set
#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