Перегрузка функции в C++ передача аргументов по значению или по ссылке
Если у нас есть этот пример кода функций в 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 overloaded, потому что она не может передать по ссылке аргумент const к параметру non-const. Но, как бы вы сделали, чтобы вызвать вторую функцию перегрузки foo? Если я рядом ... путь:
int i = 10;
foo( i);
это происходит неоднозначная ошибка, потому что обе функции действительны для этого аргумента.
в этой ссылке https://stackoverflow.com/a/5465379/6717386 это объясняется одним из способов его решения: использование объектов вместо встроенных типов и выполнение частного конструктора копирования, поэтому он не может сделать копию значения объекта, и его нужно назвать второй функцией перегрузки foo и передать объект по ссылке. Но, есть ли какой-либо способ со встроенным типы? Я должен изменить имя функции, чтобы избежать перегрузки?
5 ответов
вы можете выполнить приведение (функции), чтобы выбрать функцию перегрузки:
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)
просто вызовет второй код, и все в порядке.
очень странный дизайн, но если вы хотите... Я предложу такое же странное решение, как и ваш дизайнXreference в сигнатуру функции. Затем в функции вы можете проверить, что вам нужно сделать, используя std::is_lvalue_reference
, std::is_rvalue_reference
.
Что-то вроде этого!--7-->
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
}
несмотря на хороший ответ @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 &)
как и ожидалось.
другой:
#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&)
}