How to define non-member operator overload for class template?

The simpler way is to put the function in the class:

template <int n> struct MyClass {
  MyClass() = default;

  template <typename REP, typename PERIOD>
  constexpr MyClass(const std::chrono::duration<REP, PERIOD> &d) noexcept
      : num(d.count()) {}

    friend bool operator==(MyClass lhs, MyClass rhs) { return lhs.num == rhs.num; }


  int num = n;
};

Demo


This doesn't work:

if (m1 == 10ns)

because when we're doing lookup on operator== between MyClass<0> and std::chrono::duration<???, std::nano>, the only operator we find is:

template <int n>
bool operator==(MyClass<n> lhs, MyClass<n> rhs);

This isn't a match - 10ns is not a MyClass<n> for any n, so template deduction fails. To write a non-member equality operator, you would need to match against any duration:

template <int n, class R, class P> bool operator==(MyClass<n>, duration<R,P> );

in both directions:

template <int n, class R, class P> bool operator==(duration<R,P>, MyClass<n> );

In addition to the operator you already have. That would work, and is sometimes even necessary.

A simpler approach would be to declare your operator== as non-member friend, as Jarod42 suggests. The reason this works is that where your non-member function was a function template, the friend is not. So lookup on m1 == 10ns finds the function:

bool operator==(MyClass<0>, MyClass<0>);

10ns is convertible to MyClass<0>, which is allowed in this context, so this works. That conversion is very cheap, so no worries there. And you just have to write the one function.