【问题标题】:Ambiguous Reference/Value Versions of Functions模糊的引用/值版本的函数
【发布时间】:2011-05-02 12:49:10
【问题描述】:

考虑以下函数原型:

void Remove(SomeContainer& Vec, const std::size_t Index);

SomeContainer Remove(SomeContainer Vec, const std::size_t Index);

第二个是按照第一个来实现的。也就是说,除了一个是按引用传递,另一个是按值传递外,它们在各个方面的功能都是相同的。

然而,GCC 表示在这种情况下这些是模棱两可的,即使第一种形式是唯一不返回值的形式:

Remove(SomeContainer, 123);

是否有任何解决方法,或者我必须为每个表单提供不同的名称?

【问题讨论】:

  • 返回类型 AFAIK 无法解析重载函数。

标签: c++ overloading ambiguity


【解决方案1】:

返回类型不是函数重载的基础。
函数的重载只能符合以下条件之一:

  1. 参数数量
  2. 参数类型 &
  3. 参数序列

调用者可以忽略返回类型,因此它不是函数重载的有效标准。

如上所述,按值传递和传递引用会给编译器造成歧义。例如:

void doSomething(int i)
{
}

void doSomething(int &i)
{
}

int main()
{
    int val = 10;
    doSomething(val);   //Ambiguous
}

这里编译器无法确定将val 传递给doSomething() 的哪个版本。它可以对任何版本进行有效的函数调用,因此它在编译时寻求帮助(因为这是静态链接)并将调用标记为模棱两可。

以防万一。重命名函数或传递指针参数是一种选择/偏好,这将使两个函数重载(名称相同但参数类型不同)。但是,在选择首选项时,重要的是要考虑功能将要执行的要求和操作。就个人而言,我不会仅仅为了重载而选择指针。如果我确实需要重新设置或使我的参数指向不同的变量,那么选择指针参数是有意义的。

简单的方法是只有两个不同的函数名。没有任何开销,并且与任何其他函数调用一样高效。

【讨论】:

  • 传递引用/值也被忽略,那么,我假设?
  • 按引用传递和按值传递算作不同的类型,完全没问题。在 C++ 中,潜在的歧义不是错误。问题在于尝试调用它时,因为编译器不知道 5 应该是 int 还是 int&
  • @Als 那么在这种情况下通常会做什么呢?是函数刚刚重命名,还是接受参数的表单改为接受指针?
  • @Oli:对,我在想你是否有int x = 5; foo(x);。我的措辞肯定很糟糕。
  • @Als:不,这不是真的。 intint& 被认为是不同的类型。
【解决方案2】:

如前所述,不考虑返回类型进行重载。但是,编译器确实考虑纯值并引用不同的类型,但它通常不知道要调用哪个版本。换句话说,有两个仅在参数是按值传递还是按引用传递不同的重载函数在您尝试调用它之前都可以:潜在的歧义不是 C++ 中的错误。

例子:

void f(int) {
    cout << "value\n";
}

void f(int&) {
    cout << "reference\n";
}

int main() {
    int  val = 42;

    f(val); // Error! Ambiguous.
    f(static_cast<int>(val)); // OK: The type is int. Will print "value"
}

但是,我不知道如何表示您想要f(int&amp;),所以这并没有太多实际用途——我只是想阐明 C++ 重载的工作原理。

【讨论】:

    【解决方案3】:

    您可以对编译器和您的函数的用户有所帮助,方法是选择更具区别性的名称:

    Container Removed( const Container& c, size_t index );
    void Remove( Container& c, size_t index );
    

    const 添加到不可变版本还会阻止用户意外调用命令式变体(编译器不允许这样做,至少对于const 容器不会)。

    【讨论】:

      【解决方案4】:

      通过引用/值传递不用于确定函数重载,因为编译器无法知道哪个是必需的 - 对于作为参数传递的值,两者都是同样好的匹配。正如其他人指出的那样,从不考虑返回类型。

      【讨论】:

      • 这不正确,正如我在上面指出的那样。您可能同时拥有void f(int)void f(int&amp;) - 问题出在尝试调用它时。
      • 我的意思是“不用于确定函数重载”部分。它:定义 void f(int) 和 void f(int&) 将编译得很好,因为编译器认为它们是不同的重载。
      • 我还希望,如果您调用f(5);,这应该调用int 版本,因为您无法传递对5 的引用。但是int x = 5; f(x); 会给出关于歧义的错误。
      猜你喜欢
      • 2015-04-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-07-08
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多