C++中按值或按引用传递参数的函数重载

8mmmxcuj  于 2022-12-15  发布在  其他
关注(0)|答案(6)|浏览(189)

如果我们有这个用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重载函数,因为它不能通过引用传递常量参数给非常数参数,但是,你怎么调用第二个foo重载函数呢,如果我用下面的方法调用:

int i = 10;
foo( i);

它会发生一个不明确的错误,因为这两个函数对此参数都有效.
在此链接https://stackoverflow.com/a/5465379/6717386中,解释了一种解决方法:用对象代替内置类型,并且私有化复制构造函数,所以它不能复制对象的值,并且必须调用第二个foo重载函数,并且通过引用传递对象,但是,有没有办法处理内置类型呢,我必须改变函数名来避免重载呢?

vjrehmav

vjrehmav1#

您可以(对函数)进行强制转换以选择重载函数:

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

Demo

rta7y2nd

rta7y2nd2#

在大多数情况下,函数重载涉及不同的参数类型和不同的输入参数长度。
您的尝试通常是一个糟糕的做法,生成的编译代码依赖于编译器,代码优化甚至可能使事情变得更糟。
您可以考虑简单地向第二个方法添加第二个参数,如下所示:

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)只会调用第二个代码,这样就可以了。

k4ymrczo

k4ymrczo3#

非常奇怪的设计,但如果你想...我会提供一个解决方案,因为你的设计奇怪使用 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
}
rryofs0p

rryofs0p4#

尽管@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 &const int &、int &&'等)。
从上面的代码中可以看到,foo(i)将打印:
foo(整数和)
不出所料。

fnatzsnv

fnatzsnv5#

另一个:

#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&)
}
enxuqcxy

enxuqcxy6#

我只是碰巧发现了这篇文章,很惊讶没有找到典型的SFINAE解决方案。所以,你去:

#include <iostream>
#include <type_traits>

template<typename T,
    typename std::enable_if<!std::is_lvalue_reference<T>{}, int>::type = 0>
void foo(T)
{ std::cout << "foo(int)"   << std::endl; }

template<typename T,
    typename std::enable_if<std::is_lvalue_reference<T>{}, int>::type = 0>
void foo(T&)
{ std::cout << "foo(int &)" << std::endl; }
 
int main() {
    int i = 42;
    int& r = i;
    foo<decltype(i)>(i);
    foo<decltype(r)>(r);
}

Live example

相关问题