Неоднозначные ссылки / значения версий функций - PullRequest
4 голосов
/ 02 мая 2011

Рассмотрим следующие прототипы функций:

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

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

Второй реализован в терминах первого.То есть они функционально идентичны во всех отношениях, за исключением того, что один является передачей по ссылке, а другой передачей по значению.

Однако, GCC говорит, что они неоднозначны в подобных случаях, дажехотя первая форма является единственной, которая не возвращает значение:

Remove(SomeContainer, 123);

Есть ли какое-то решение для этого или мне нужно придумать разные имена для каждой формы?

Ответы [ 4 ]

5 голосов
/ 02 мая 2011

Тип возврата не является основой перегрузки функции.
Перегрузка функций возможна только по одному из следующих критериев:

  1. Нет аргументов
  2. Тип аргументов &
  3. Последовательность аргументов

Тип возврата может игнорироваться вызывающей стороной, и, следовательно, он не является допустимым критерием перегрузки функции.

Сказав выше, передача по значению и передача ссылки создаст неоднозначность для компилятора. Например:

void doSomething(int i)
{
}

void doSomething(int &i)
{
}

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

Здесь компилятор не может определить, как передать val какой версии doSomething(). Он может сделать допустимый вызов функции для любой из версий, поэтому он взывает о помощи во время компиляции (поскольку это статическое связывание) и помечает вызовы как неоднозначные.

В случае, например, ваш. Это выбор / предпочтение, чтобы переименовать функции или передать аргумент указателя, что сделает две функции перегруженными (одно и то же имя, но разные типы аргументов). Тем не менее, важно принять во внимание требование и действие, которое будет выполнять функция при выборе предпочтения. Лично я бы не выбрал указатель просто ради перегрузки. Если мне нужно переустановить аргумент или указать его аргумент на разные переменные, то имеет смысл выбрать аргумент-указатель.

Простой способ - просто иметь два разных имени функции. Нет никаких накладных расходов, и это так же эффективно, как и любой другой вызов функции.

3 голосов
/ 02 мая 2011

Как уже упоминалось, тип возвращаемого значения не рассматривается для перегрузки. Однако компилятор учитывает обычные значения и ссылается на разные типы, но обычно не знает, какую версию вызывать. Другими словами, наличие двух перегруженных функций, которые отличаются только тем, является ли параметр передачей по значению или передачей по ссылке, работает до тех пор, пока вы не попытаетесь вызвать его: Потенциальная неоднозначность не является ошибкой в ​​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&), однако, в этом нет особого практического применения - я просто пытаюсь выяснить, как работает перегрузка C ++.

2 голосов
/ 02 мая 2011

Вы могли бы немного помочь компилятору, а пользователи ваших функций , выбрав более отличительные имена:

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

Добавление const к неизменяемой версии также будет препятствоватьпользователи от случайного вызова императивного варианта (компилятор не допустит этого, по крайней мере, не для const контейнеров).

1 голос
/ 02 мая 2011

Передача по ссылке / значению не используется для определения перегрузки функции, поскольку компилятор не знает, что требуется, - оба одинаково хорошо подходят для значения, переданного в качестве параметра. И, как отмечают другие, тип возвращаемого значения никогда не учитывается.

...