A Mixin Comparator class
ADL

This can be improved. First - you're requiring a tie() member function, it'd be better to make that more of a customization point. Second - you're putting all the operators in global scope when it'd be better to hide them. Both issues can be solved with some ADL. 

The advantage of making an operator a non-member friend declared inline is that it can only be found when comparing precisely what you want. The downside to what you're doing right now is the following compiles:

struct B : Comparable&lt;B&gt; {
    ...
};

struct D {
    operator B() { ... }
};

D d1 = ...;
D d2 = ....;
if (d1 == d2) { ... }


D isn't comparable - but this code would still compile via the B conversion, which may be surprising! 

We can instead write equality like so:

namespace cmp {
    template &lt;class T&gt;
    auto tie(const T&amp; val) -&gt; decltype(val.tie()) {
        return val.tie();
    }

    template &lt;class T&gt;
    struct Comparable {
        friend bool operator==(const T&amp; lhs, const T&amp; rhs) {
            return tie(lhs) == tie(rhs);
        }
    };
}


Note that the operator here takes Ts and not Comparable&lt;T&gt;s. We know what the derived type is, so we can just use it. The nonqualified call to tie lets us write something like:

namespace foo {
    struct B : Comparable&lt;B&gt; {
        int i;
    };

    int tie(const B&amp; b) { return b.i; }
}


Customization is nice. 

Split it up

EqualityComparable and LessThanComparable are different concepts. If you split up the responsibilities, it'll make your class more useful:

namespace cmp {
    template &lt;class T&gt;
    struct EqualityComparable {
        friend bool operator==(const T&amp; lhs, const T&amp; rhs) { return tie(lhs) == tie(rhs); }
        friend bool operator!=(const T&amp; lhs, const T&amp; rhs) { !(lhs == rhs); }
    };

    template &lt;class T&gt;
    struct LessThanComparable {
        friend bool operator&lt;(const T&amp; lhs, const T&amp; rhs) { return tie(lhs) &lt; tie(rhs); }
        friend bool operator&lt;=(const T&amp; lhs, const T&amp; rhs) { return !(rhs &lt; lhs); }
        // etc.
    };

    template &lt;class T&gt;
    struct TotallyOrdered : EqualityComparable&lt;T&gt;, LessThanComparable&lt;T&gt;
    { };
}


Cross-Compare

If two classes have comparable tie()s, why not support that too?

template &lt;class T, class U&gt;
struct EqualityComparable2
{
    friend bool operator==(const T&amp; lhs, const U&amp; rhs) { return tie(lhs) == tie(rhs); }
    friend bool operator==(const U&amp; lhs, const T&amp; rhs) { return rhs == lhs; }
    // same for !=
};


Go wild.