C++ 中的函数重载按值或按引用传递参数
Function overloading in C++ passing arguments by value or by reference
如果我们在 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 参数传递给非常量参数。
但是,您将如何调用第二个 foo 重载函数?
如果我调用下一个方式:
int i = 10;
foo( i);
它发生了一个不明确的错误,因为这两个函数都对这个参数有效。
在此link 中解释了一种解决方法:使用对象而不是内置类型,并将复制构造函数私有化,因此它不能复制对象value 并且必须调用第二个 foo 重载函数并通过引用传递对象。但是,内置类型有什么办法吗?我必须更改函数名称以避免重载?
您可以对 select 重载函数进行(函数的)转换:
static_cast<void (&)(int&)>(foo)(i);
在大多数情况下,函数重载涉及不同的参数类型和不同的输入参数长度。
您的尝试通常是一种不好的做法,生成的编译代码依赖于编译器,代码优化甚至可能使事情变得更糟。
您可以考虑简单地向第二个方法添加第二个参数,如下所示:
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)
只会调用第二个代码,大家都很好。
尽管 @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
(即 int
、int &
、const int &
、int &&` 等等)。
从上面的代码可以看出,foo(i)
会打印:
foo(int &)
符合预期。
非常奇怪的设计,但如果您需要...我会提供一个与您的设计一样奇怪的解决方案 在函数签名中使用 Xreference。然后在函数中,您可以使用 std::is_lvalue_reference
、std::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
}
另一个:
#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&)
}
如果我们在 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 参数传递给非常量参数。 但是,您将如何调用第二个 foo 重载函数? 如果我调用下一个方式:
int i = 10;
foo( i);
它发生了一个不明确的错误,因为这两个函数都对这个参数有效。
在此link 中解释了一种解决方法:使用对象而不是内置类型,并将复制构造函数私有化,因此它不能复制对象value 并且必须调用第二个 foo 重载函数并通过引用传递对象。但是,内置类型有什么办法吗?我必须更改函数名称以避免重载?
您可以对 select 重载函数进行(函数的)转换:
static_cast<void (&)(int&)>(foo)(i);
在大多数情况下,函数重载涉及不同的参数类型和不同的输入参数长度。
您的尝试通常是一种不好的做法,生成的编译代码依赖于编译器,代码优化甚至可能使事情变得更糟。
您可以考虑简单地向第二个方法添加第二个参数,如下所示:
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)
只会调用第二个代码,大家都很好。
尽管 @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
(即 int
、int &
、const int &
、int &&` 等等)。
从上面的代码可以看出,foo(i)
会打印:
foo(int &)
符合预期。
非常奇怪的设计,但如果您需要...我会提供一个与您的设计一样奇怪的解决方案 在函数签名中使用 Xreference。然后在函数中,您可以使用 std::is_lvalue_reference
、std::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
}
另一个:
#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&)
}