Gabrielle de Grimouard
Gabrielle de Grimouard

Reputation: 2005

Generic overloading operator

I like to play with auto and decltype, and then I wondered if it would be possible to do generic operators with auto. Indeed, since c++14 et can do this:

decltype(auto) add(auto v1, auto v2) {
  return v1 + v2;
}

however, I wanted to try it with templated classes containing values like this one:

template<typename T>
class test {
 public:
  T value;
  test(T val) {
    value = val;
  }
};

and then I would need an overloading operator + like this one which work:

template<typename T>
T operator+(test<T> const& t1, test<T> const& t2) {
    return t1.value + t2.value;
}

which is already quite great. However, I would like a generic operator+ which can be use by multiple classes. Like these one:

decltype(t1.value) operator+(auto const& t1, auto const& t2) {
    return t1.value + t2.value;
}

template<typename T>
T operator+(auto const& t1, auto const& t2) {
    return t1.value + t2.value;
}

which doesn't not compile.

In C++14/17, is there a way to make generics overloading operators which would be able to be used by many classes like the ones I wrote ?

PS: here the code for your tests which compile with gcc7 snapshot but not with clang which seems to don't allow the auto in functions prototypes : link to compiler explorer code

#include <iostream>

template<typename T>
class test {
 public:
  T value;
  test(T val) {
    value = val;
  }
};

template<typename T>
T operator+(test<T> const& t1, test<T> const& t2) {
    return t1.value + t2.value;
}

decltype(auto) add(auto v1, auto v2) {
  return v1 + v2;
}

int main() {
  decltype(5) v1 = 5;
  decltype(v1) v2 = 3;
  test<decltype(v1)> t(v1);
  test<decltype(v2)> t2(v2);

  return add(t, t2);
}

Upvotes: 2

Views: 311

Answers (1)

Holt
Holt

Reputation: 37616

If I understood your question, you can use a trailing return type:

auto operator+(auto const& t1, auto const& t2) -> decltype(t1.value + t2.value) {
    return t1.value + t2.value;
}

For compiler that do not accept auto for parameters, you can simply fall backs to two template parameters:

template <typename U, typename V>
auto operator+(U const& t1, V const& t2) -> decltype(t1.value + t2.value) {
    return t1.value + t2.value;
}

As @Jarod42 mentioned in the comments, you probably want to use decltype(t1.value + t2.value) instead of decltype(t1.value) to handle conversions and promotions correctly.

Upvotes: 3

Related Questions