Разрешить неоднозначный вызов функции, когда единственным отличием является параметр, переданный по ссылке или путем копирования

#c

#c

Вопрос:

Допустим, у меня есть класс, реализующий эти два метода :

 void foo(const int a);
void foo(const int amp; a);
  

Как мне разрешить неоднозначный вызов, например :

 int bar = 42;
foo(bar);
  

Редактировать

Оба метода являются виртуальными, унаследованными от двух разных родителей, выполняющих разные действия. Я хотел бы иметь возможность выбирать один из них при вызове.

Пример кода большего размера :

 class B{
  virtual void foo(const int a) = 0;
};

class C{
  virtual void foo(const int amp; a) = 0;
};

class A : public B, public C{
  void foo(const int a){
    // do something
  }
  void foo(const int amp; a){
    // do something else
  }
};

int main(){
  A a;
  int bar = 42;
  a.foo(bar);
}

  

B и C class не написаны мной в моем реальном случае, но я должен их использовать.

Комментарии:

1. Я думаю, вам нужно уточнить свой вопрос, вы хотите знать, как будет разрешен этот случай, или вы хотите, чтобы он работал? Если первый не будет, если второй, тогда вы должны указать критерии.

2. Измените имя либо B::foo , либо C::foo . Обратите внимание, что в B::foo const int параметр, the const не является частью подписи и не имеет отношения к вызывающим.

3. Я не могу изменить код C или B. И const используется для того, чтобы сделать обязательным не изменять значение, переданное при реализации метода.

4. Вы просите невозможного… Но, вероятно, это проблема XY : чего вы действительно хотите достичь. Дайте больше информации.

5. @JHBonarius здесь очень весело 🙂 но я работаю с чужим кодом и стараюсь свести к минимуму количество переписывания, повторяю: чего я хочу добиться, так это, начиная с этого, иметь возможность выбирать, какой метод будет вызываться.

Ответ №1:

Обычным решением такого рода проблем является использование пары промежуточных классов для переименования этих функций.

 struct intermediate1 : base1 {
    virtual void f(int x) = 0;
    void foo(int x} { f(x); }
};

struct intermediate2 : base2 {
    virtual void g(const intamp; x) = 0;
    void foo(const intamp; x} { g(x); }
};
  

Теперь ваш класс может быть производным от двух промежуточных классов вместо двух исходных базовых классов, и ваш код может переопределять f(whatever) g(whatever) и вызывать их, а не конфликтующие foo версии.

Если вам нравятся функции оформления, вы можете пометить обе эти версии foo as final .

Комментарии:

1. Кажется грязным, но выполняет свою работу.

2. @Welgriv — к сожалению, просто дошло до того, что это не касается виртуальности двух версий foo . Я переписал ответ, чтобы исправить это; если это не решает вашу проблему, не стесняйтесь отозвать свое согласие. (В общем, вам следует подождать день или около того, прежде чем принимать ответ, на случай, если кто-то придумает лучший).

Ответ №2:

Способ c 11 — использовать значение rvalue ref для 1-й перегрузки:

   void foo(intamp;amp; rvalue);
  void foo(intamp; lvalue);
  

подробнее о rvalue ref на:
https://en.cppreference.com/w/cpp/language/reference

Для проблемы множественного наследования:

  struct D:C{
     virtual void foo(intamp;amp;, std::nullptr_t)=0;
 private:
     void foo(int v) final { return foo(std::move(v),nullptr); };
 };
 
 struct A:B,D{
    void foo(intamp;amp;, std::nullptr_t=nullptr) override;
    void foo(intamp; ) override;
 };
  

Комментарии:

1. Почему вы сделали это вики сообщества? С этим проблем нет, мне просто любопытно 🙂

2. Ссылка на значение Rvalue. Если вам это не нравится, я не настаиваю.

3. Я понимаю вашу точку зрения, но в моем случае я не могу выдвинуть никаких гипотез относительно типа параметра, заданного при вызове.

4.Итак, у вас проблема с множественным наследованием. Оберните B класс в производный от декоратора класс, из которого A будет получен. Но дальнейшее наследование от A будет сложным: класс-оболочка должен сделать foo final override пересылку в отдельную виртуальную функцию, которую A и дочерние элементы будут override .