Reflecting mirrors

Detect transparent comparators

Notes published the
1 - 2 minutes to read, 372 words

After writing about std::map::lower_bound and transparent comparators, a question that followed up was "How to detect at compile time if the comparator is transparent or not?".

A comparator is transparent if it defines an is_transparent type.

struct comparator0{
	bool is_transparent;
	// operator() and eventually others
};
struct comparator1{
	using is_transparent = int;
	// operator() and eventually others
};
struct comparator2{
	using is_transparent = void;
	// operator() and eventually others
};

Both comparator1 and comparator2 are transparent comparators, as long as the tag type is_transparent is defined, thus something like using a = comparator1::is_transparent; is valid. comparator0 is thus not a transparent comparator.

Looking back at how to detect member variables at compile time, it is possible to define a similar set of structures for querying if is_transparent is defined or not.

But contrary to the approach used for member variables, we cannot use decltype and void() for specializing a template.

For types, we can use std::void_t, which converts any type to…​ void.

#include <type_traits>
#include <map>

template <typename T, typename = void>
struct is_transparent_comparator : std::false_type{};

template <typename T>
struct is_transparent_comparator<T, std::void_t<typename T::is_transparent>> : std::true_type {};

struct comparator0{
	bool is_transparent;
	// operator() and eventually others
};
struct comparator1{
	using is_transparent = int;
	// operator() and eventually others
};
struct comparator2{
	using is_transparent = void;
	// operator() and eventually others
};
struct incomplete;
struct comparator3{
	using is_transparent = incomplete;
	// operator() and eventually others
};


static_assert(not is_transparent_comparator<comparator0>::value);
static_assert(    is_transparent_comparator<comparator1>::value);
static_assert(    is_transparent_comparator<comparator2>::value);
static_assert(    is_transparent_comparator<comparator3>::value);
static_assert(    is_transparent_comparator<std::less<>>::value);
static_assert(not is_transparent_comparator<std::map<int,int>::key_compare>::value);
static_assert(    is_transparent_comparator<std::map<int,int,std::less<>>::key_compare>::value);

Note that if you do not have access to C++17 yet, then template <class> struct my_void_t { using type = void; }; is a good enough replacement for std::void_t.


Do you want to share your opinion? Or is there an error, some parts that are not clear enough?

You can contact me anytime.