【问题标题】:Function overloading in C++ passing arguments by value or by referenceC++ 中的函数重载按值或按引用传递参数
【发布时间】:2023-03-04 16:23:02
【问题描述】:

如果我们有这个 C++ 中的示例函数代码

void foo(int x)  { std::cout << "foo(int)"   << std::endl; }
void foo(int& x) { std::cout << "foo(int &)" << std::endl; }

是否可以区分调用哪个函数对调用参数进行任何修改?

如果函数 foo 以下列方式调用:

foo( 10);

i = 10;
foo( static_cast<const int>(i));

foo( static_cast<const int&>(i)); 

它被称为第一个 foo 重载函数,因为它不能通过引用将 const 参数传递给非 const 参数。 但是,如何调用第二个 foo 重载函数? 如果我调用下一个方式:

int i = 10;
foo( i);

它发生了一个模棱两可的错误,因为这两个函数都对该参数有效。

在此链接https://stackoverflow.com/a/5465379/6717386 中,解释了解决它的一种方法:使用对象而不是内置类型并使用私有的复制构造函数,因此它不能复制对象值,它必须被称为第二个 foo 重载函数并通过引用传递对象。但是,内置类型有什么办法吗?我必须更改函数名称以避免重载?

【问题讨论】:

  • 你试过foo( static_cast&lt;int&amp;&gt;(i));吗?
  • 您可以改用void foo(int x)void foo(int *x)
  • @mvidelgauz 是的,我已经尝试过了。与上述相同的错误。 :(
  • @DimChtz 是的,这种方式有效。但是使用引用?
  • 最简单的解决方案是编写更好的函数。或者将它们放在不同的命名空间中。

标签: c++ c++11 overloading


【解决方案1】:

你可以做一个(函数的)强制转换来选择重载函数:

static_cast<void (&)(int&)>(foo)(i);

Demo

【讨论】:

  • 谢谢,它工作正常!但是,我正在使用类和方法尝试您的解决方案,它出现错误 error: invalid static_cast from type '' to type 'void (&)(Punto&)'。这是here link:
  • @CarlosUrda 您需要在方法指针中包含类名,例如static_cast(&MyClass::foo);
  • @CarlosUrda:语法更丑,见Demo
  • @CarlosUrda: const 缺少该方法的演员表:Demo
【解决方案2】:

在大多数情况下,函数重载涉及不同的参数类型和不同的输入参数长度。

您的尝试通常是一种不好的做法,生成的编译代码取决于编译器,代码优化甚至可能使事情变得更加糟糕。

您可以考虑简单地为第二种方法添加第二个参数,如下所示:

void foo(int x)  { std::cout << "foo(int)"   << std::endl; }
void foo(int& x, ...) { std::cout << "foo(int &, ...)" << std::endl; }

... 可以是布尔类型,例如:bool anotherFunction

所以调用foo(param1, param2) 只会调用第二个代码,每个人都很好。

【讨论】:

  • 依赖编译器?除非你的编译器坏了,否则没有理由改变行为。
  • 谢谢,但我不喜欢你的解决方案。我正在尝试使用相同的函数名称来设置类中的 getter。 class Circulo { public: void centro( const Punto&amp;); // setter void centro( Punto&amp;) const; // getter private: Punto centro_; };
  • 抱歉,问题不够明确。我只是认为保持简单的事情简单是关键。但是,关于 getter 和 setter,为了获得更易读的代码,您可以考虑不为您的 getter 使用参数。如果您遵循这种方法,您仍然可以避免此错误,并且您的代码仍然非常干净。
  • @CarlosUrda: 然后简单地做 `class Circle { const Point& Center(); const;Point&Center(); /* ... */};
  • @CarlosUrda - 我的观点是,当您考虑在函数中提供 NULL 时,这两个函数在语法上是相同的。因此,歧义。但是,就像我说的,如果您没有尝试为您的 getter 方法使用参数。我们现在可能正在讨论其他事情:)
【解决方案3】:

非常奇怪的设计,但如果你愿意...我会提供一个和你的设计一样奇怪的解决方案 在函数签名中使用 Xreference。然后在函数中,您可以使用std::is_lvalue_referencestd::is_rvalue_reference 检查您需要做什么。
像这样的

template<class T>
void foo(T&& x)
{
  static_assert(std::is_same<std::decay_t<T>, int>::value, "!"); 
  if (std::is_rvalue_reference<T&&>::value)
    std::cout << "do here what you want in foo(int x)";
  else
    std::cout << "do here what you want in foo(int & x)";
}

int main()
{
  int x = 5;
  foo(x); //"do here what you want in foo(int x)" - will be printed
  foo(std::move(x)); //"do here what you want in foo(int & x)" - will be printed
}

【讨论】:

    【解决方案4】:

    尽管@Jarod42 的回答很好,但作为替代解决方案,您可以依赖模板化入口点和内部函数的重载(当然,如果您不想处理显式转换)。
    它遵循一个最小的工作示例:

    #include<type_traits>
    #include<iostream>
    #include<utility>
    
    void foo_i(char, int x)  { std::cout << "foo(int)"   << std::endl; }
    void foo_i(int, int &x) { std::cout << "foo(int &)" << std::endl; }
    
    template<typename T>
    void foo(T &&t) {
        static_assert(std::is_same<std::decay_t<T>, int>::value, "!");
        foo_i(0, std::forward<T>(t));
    }
    
    int main() {
        foo( 10);
        int i = 10;
        foo( static_cast<const int>(i));
        foo( static_cast<const int &>(i)); 
        foo(i);
    }
    

    static_assert 用于检查参数是否涉及int(即intint &amp;const int &amp;、int &&` 等)。

    从上面的代码可以看出,foo(i) 会打印出来:

    foo(int &)

    正如预期的那样。

    【讨论】:

      【解决方案5】:

      另一个:

      #include <iostream>
      #include <functional>
      
      void foo(int x)
      {
          std::cout << "foo(int)\n";
      }
      
      template<typename T>
      void foo(T&& x)
      {
          std::cout << "foo(int&)\n";
      }
      
      int main()
      {
          int i = 10;
          foo(i);           // foo(int)
          foo(std::ref(i)); // foo(int&)
      }
      

      【讨论】:

      • 糟糕的解决方案。一般来说,重载函数的唯一参数是 Xreference 是一个坏主意。例如: const int i = 10;富(一);将打印“foo(int&)\n”
      • @AndreyNekrasov 好吧,也许是另一个糟糕的解决方案,但是const int i = 10; foo(i); 在我的 gcc 中打印 foo(int)。
      猜你喜欢
      • 2011-02-22
      • 2015-05-21
      • 1970-01-01
      • 2014-07-11
      • 2012-10-28
      • 2019-05-07
      • 2012-03-12
      • 2013-09-15
      • 2011-01-08
      相关资源
      最近更新 更多