lundi 29 juin 2015

Amibiguous operator in reference class?


I am attempting to create a class that mimics a reference to some value. To do that I want to define operator overloads so that it behaves appropriately. When I do that, operator+ resolves correctly, but operator* complains with error: use of overloaded operator '*' is ambiguous (with operand types 'ref<int>' and 'int') (at least in Clang 3.4).

Here's what I've done (with most things made explicit and removing all of the extra stuff):

template <typename T> class ref {
private:
  T &val;

public:
  ref(T &r) : val(r) {}

  template <typename R> ref<T> &operator=(R const &rhs) {
    val = rhs;
    return *this;
  }

  // BINOP_TY(+);
  template <typename L, typename R>
  friend auto operator+(L lhs, ref<R> rhs) -> decltype((lhs) + (rhs.val));

  template <typename L, typename R>
  friend auto operator+(ref<L> lhs, R rhs) -> decltype((lhs.val) + (rhs));

  template <typename L, typename R>
  friend auto operator+(ref<L> lhs, ref<R> rhs)
      -> decltype((lhs.val) + (rhs.val));

  // BINOP_TY(*);
  template <typename L, typename R>
  friend auto operator*(L lhs, ref<R> rhs) -> decltype((lhs) * (rhs.val));

  template <typename L, typename R>
  friend auto operator*(ref<L> lhs, R rhs) -> decltype((lhs.val) * (rhs));

  template <typename L, typename R>
  friend auto operator*(ref<L> lhs, ref<R> rhs)
      -> decltype((lhs.val) * (rhs.val));
};

// BINOP(+);
template <typename L, typename R>
auto operator+(L lhs, ref<R> rhs) -> decltype((lhs) + (rhs.val)) {
  return lhs + rhs.val;
}

template <typename L, typename R>
auto operator+(ref<L> lhs, R rhs) -> decltype((lhs.val) + (rhs)) {
  return lhs.val + rhs;
}

template <typename L, typename R>
auto operator+(ref<L> lhs, ref<R> rhs) -> decltype((lhs.val) + (rhs.val)) {
  return lhs.val + rhs.val;
}

// BINOP(*);
template <typename L, typename R>
auto operator*(L lhs, ref<R> rhs) -> decltype((lhs) * (rhs.val)) {
  return lhs * rhs.val;
}

template <typename L, typename R>
auto operator*(ref<L> lhs, R rhs) -> decltype((lhs.val) * (rhs)) {
  return lhs.val * rhs;
}

template <typename L, typename R>
auto operator*(ref<L> lhs, ref<R> rhs) -> decltype((lhs.val) * (rhs.val)) {
  return lhs.val * rhs.val;
}

// Works.
void plus(ref<int> r, int i) {
  r = r + i;
}

// Fails.
void mult(ref<int> r, int i) {
  r = r * i;
}

Full output:

$ clang++ -std=c++11 ref2.cpp
ref2.cpp:75:13: error: use of overloaded operator '*' is ambiguous (with operand types 'ref<int>' and 'int')
      r = r * i;
          ~ ^ ~
ref2.cpp:29:19: note: candidate function [with L = int, R = int]
      friend auto operator*(ref<L> lhs, R rhs) -> decltype((lhs.val) * (rhs));
                  ^
ref2.cpp:59:10: note: candidate function [with L = int, R = int]
    auto operator*(ref<L> lhs, R rhs) -> decltype((lhs.val) * (rhs)) {
         ^
1 error generated.

What am I missing?


Aucun commentaire:

Enregistrer un commentaire