简体   繁体   中英

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

I have a class template that has a constructor taking an std::chrono::duration, because I want to be able to use the chrono_literals to construct it. Now, I'm trying to define a non-member operator overload but I can't get it to work with the duration constructor:

#include <chrono>
#include <iostream>

using namespace std;

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()) {}

  int num = n;
};

template <int n> bool operator==(MyClass<n> lhs, MyClass<n> rhs) {
  return lhs.num == rhs.num;
}

int main(int argc, char *argv[]) {
  using namespace std::literals::chrono_literals;

  MyClass<0> m1(10ns);

  if (m1 == 10ns)
    cout << "Yay!" << endl;
  return 0;
}

gcc is giving this error for rejecting my overload:

main.cpp:34:12: error: no match for ‘operator==’ (operand types are ‘MyClass<0>’ and ‘std::chrono::nanoseconds {aka std::chrono::duration<long int, std::ratio<1l, 1000000000l> >}’)
     if (m1 == 10ns)
         ~~~^~~~~~~
main.cpp:23:6: note: candidate: template<int n> bool operator==(MyClass<n>, MyClass<n>)
 bool operator == (MyClass<n> lhs, MyClass<n> rhs)
      ^~~~~~~~
main.cpp:23:6: note:   template argument deduction/substitution failed:
main.cpp:34:15: note:   ‘std::chrono::duration<long int, std::ratio<1l, 1000000000l> >’ is not derived from ‘MyClass<n>’
     if (m1 == 10ns)
               ^~~~

Is there any way to make this work?

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM