C++ 当唯一的区别是通过引用或复制传递的参数时,解析ambigus函数调用

C++ 当唯一的区别是通过引用或复制传递的参数时,解析ambigus函数调用,c++,C++,假设我有一个类实现了这两种方法: void foo(const int a); void foo(const int & a); 如何解决不明确的呼叫,如: int bar = 42; foo(bar); 编辑 这两种方法实际上都是从两个不同的父母那里继承来的,做着不同的事情。我想有能力选择一个在电话 更大的代码示例: class B{ virtual void foo(const int a) = 0; }; class C{ virtual void foo(const

假设我有一个类实现了这两种方法:

void foo(const int a);
void foo(const int & a);
如何解决不明确的呼叫,如:

int bar = 42;
foo(bar);
编辑 这两种方法实际上都是从两个不同的父母那里继承来的,做着不同的事情。我想有能力选择一个在电话

更大的代码示例:

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

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

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

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


B
C
类不是我在真实情况下编写的,但我必须使用它们。

C++11方法是对第一个重载使用右值引用:

  void foo(int&& rvalue);
  void foo(int& lvalue);
有关右值参考的更多信息,请访问:

对于多重继承问题:

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

c++11的方法是对第一个重载使用右值ref:

  void foo(int&& rvalue);
  void foo(int& lvalue);
有关右值参考的更多信息,请访问:

对于多重继承问题:

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

这类问题的通常解决方案是使用一对中间类来重命名这些函数

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

struct intermediate2 : base2 {
    virtual void g(const int& x) = 0;
    void foo(const int& x} { g(x); }
};
现在,您的类可以从两个中间类而不是两个原始基类派生,并且您的代码可以覆盖
f(whatever)
g(whatever)
并调用它们,而不是冲突的
foo
版本


如果您喜欢装饰函数,可以将
foo
的两个版本都标记为
final

这类问题的常见解决方案是使用一对中间类重命名这些函数

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

struct intermediate2 : base2 {
    virtual void g(const int& x) = 0;
    void foo(const int& x} { g(x); }
};
现在,您的类可以从两个中间类而不是两个原始基类派生,并且您的代码可以覆盖
f(whatever)
g(whatever)
并调用它们,而不是冲突的
foo
版本



如果您喜欢装饰函数,您可以将
foo
的这两个版本都标记为
final

我想您需要澄清您的问题,您想知道这个问题是如何解决的还是希望它起作用?如果第一个不是第二个,那么您应该指定条件。更改B::foo或C::foo的名称。注意,在B::foo中,
const int
参数,
const
不是签名的一部分,与调用方无关。我不能修改C或B代码。而
const
用于强制在实现方法时不修改传递的值。。。但这可能是一个问题:你真正想要实现什么。提供更多的背景资料。@JHBonarius这里有很多乐趣:-)但是我使用其他人的代码并尽量减少重写的次数,我重复一遍:我想实现的是,从这开始,能够选择调用哪个方法。我想你需要澄清你的问题,你想知道这个案子是如何解决的还是你想让它起作用?如果第一个不是第二个,那么您应该指定条件。更改B::foo或C::foo的名称。注意,在B::foo中,
const int
参数,
const
不是签名的一部分,与调用方无关。我不能修改C或B代码。而
const
用于强制在实现方法时不修改传递的值。。。但这可能是一个问题:你真正想要实现什么。提供更多的背景资料。@JHBonarius这里有很多乐趣:-)但是我使用其他人的代码并尽量减少重新编写的次数,我重复一遍:我想实现的是,从这一点开始,能够选择调用哪个方法。你为什么要将其作为一个社区wiki?没问题,我只是好奇:)右值引用。如果你不喜欢,我不坚持。我明白你的意思,但在我的情况下,我不能对调用中给出的参数类型做任何假设。所以你对多重继承有问题。将
B
类包装在将从中派生
a
的装饰器派生类中。但是,从A继承的进一步操作将是复杂的:包装类必须使foo成为一个
final
override
转发到一个独特的虚拟函数,该函数
A
,子函数将
override
。为什么要将其作为一个社区wiki?没问题,我只是好奇:)右值引用。如果你不喜欢,我不坚持。我明白你的意思,但在我的情况下,我不能对调用中给出的参数类型做任何假设。所以你对多重继承有问题。将
B
类包装在将从中派生
a
的装饰器派生类中。但是从A继承的进一步操作将是复杂的:包装类必须使foo成为一个
final
重写
转发到一个独特的虚拟函数,该函数
A
和子函数将
重写
。看起来很脏,但可以完成任务。@Welgriv--不幸,它只是意识到这并没有处理两个版本的
foo
的虚拟性。我已经重写了答案来解决这个问题;如果它不能解决您的问题,请随时撤回您的接受。(一般来说,你应该等一天左右再接受一个答案,以防有人想出更好的答案)。看起来很脏,但要做好这项工作。@Welgriv——不幸的是,这并不能解决
foo
两个版本的虚拟性问题。我已经重写了答案来解决这个问题;如果它不能解决您的问题,请随时撤回您的接受。(一般来说,你应该等一天左右再接受答案,以防有人想出更好的答案)。