Explanation
Let's break it down step-by-step:
(T*)(0)
: pretend there's an object of type T
at address 0; the type of this subexpression is a pointer
*(T*)(0)
: pretend there's an object of type T
at address 0; the type of this subexpression is a reference, due to the asterisk in front dereferencing the pointer. It looks kind of like a null pointer dereference, but more on that later.
*(Arg*)(0)
: pretend there's an object of type Arg
at address 0; same pattern as T
*(T*)(0) == *(Arg*)(0)
: this is equivalent to calling operator==<T, Arg>( *(T*)(0), *(Arg*)(0) )
with the additional convenience of letting the compiler figure out where the operator is defined.
- If a user-defined
operator==
does not exist, then the CHECK
namespace operator will be matched instead. It's a "catch all" template.
decltype(*(T*)(0) == *(Arg*)(0))
: decltype
says "don't execute the subexpression in the parentheses; just give me its type". In this case, the type is the return type of the operator==
call.
- No comparison operation actually occurs, nor any derefences into memory.
std::is_same<decltype(*(T*)(0) == *(Arg*)(0)), No>::value
: std::is_same
's value
is true
if the types are identical, or false
otherwise.
::value
is a static constexpr bool
- The two type arguments are the
decltype(...)
and struct CHECK::No
.
- A real-world
operator==
typically returns bool. Occasionally it may return a user-defined type. It's unlikely that someone will write their custom operator==
to return CHECK::No
, and this code is relying upon that assumption.
enum { value = !std::is_same<...>::value }
: An enum is always a compile-time constant, works on older C++ compilers & specs (like C++03, where constexpr
didn't exist), is compatible with constexpr
, and does not require storage.
static constexpr bool value = !std::is_same<...>::value;
would have been equivalent.
Issues with the example code:
- Technically it's illegal to dereference a null pointer;
std::declval
is a safe alternative.
- Technically someone could write
CHECK::No operator==(const Foo&, const Bar&)
, which would fool the check into thinking the operator was undefined.
- The
operator==
in the CHECK namespace could shadow a globally defined operator== definition, resulting in a false negative.
Alternative Implementation
To fix the above issues and "simplify", one method is to use SFINAE. Although "simpler" is subjective here.
[edit] Link to working version: http://coliru.stacked-crooked.com/a/e9cc48729d53b6c6 , and updated code below
template <typename T, typename Arg = T>
class EqualExists {
template <class U = T, class V = Arg, bool Exists = !!sizeof(std::declval<U>() == std::declval<V>())>
static std::true_type Func(const T&, const Arg&);
template <class U, class V>
static std::false_type Func(const U&, const V&);
public:
static constexpr bool value = decltype(Func(std::declval<T>(), std::declval<Arg>()))::value;
};
[edit] My original answer had a bug : did not use template args U and V in the Exists computation, and did fail to compile on gcc. (worked on msvc for some reason)
template <class U, class V, bool Exists = !!sizeof(std::declval<T>() == std::declval<Arg>())>
static std::true_type Func(const T&, const Arg&);