Что означает "int & foo()" в С++?

При чтении этого объяснения на lvalues ​​и rvalues ​​эти строки кода торчали мне:

int& foo();
foo() = 42; // OK, foo() is an lvalue

Я попробовал это в g++, но компилятор говорит "undefined ссылка на foo()". Если я добавлю

int foo()
{
  return 2;
}

int main()
{
  int& foo();
  foo() = 42;
}

Он компилируется отлично, но его запуск дает segmentation fault. Только строка

int& foo();

сам компилируется и запускается без проблем.

Что означает этот код? Как вы можете присвоить значение вызову функции и почему это не значение r?

Ответ 1

Объяснение предполагает, что существует некоторая разумная реализация для foo, которая возвращает ссылку lvalue на действительный int.

Такая реализация может быть:

int a = 2; //global variable, lives until program termination

int& foo() {
    return a;
} 

Теперь, поскольку foo возвращает ссылку lvalue, мы можем присвоить что-то возвращаемому значению, например:

foo() = 42;

Это приведет к обновлению глобального a значением 42, которое мы можем проверить, обратившись к переменной напрямую или вызов foo снова:

int main() {
    foo() = 42;
    std::cout << a;     //prints 42
    std::cout << foo(); //also prints 42
}

Ответ 2

Все остальные ответы объявляют статику внутри функции. Я думаю, это может вас смутить, поэтому взгляните на это:

int& highest(int  & i, int  & j)
{
    if (i > j)
    {
        return i;
    }
    return j;
}

int main()
{
    int a{ 3};
    int b{ 4 };
    highest(a, b) = 11;
    return 0;
}

Поскольку highest() возвращает ссылку, вы можете присвоить ей значение. Когда это будет выполнено, b будет изменено на 11. Если вы изменили инициализацию так, чтобы a был, скажем, 8, тогда a будет изменен на 11. Это код, который может действительно служить цели, в отличие от других примеров.

Ответ 3

int& foo();

Объявляет функцию с именем foo, которая возвращает ссылку на int. Что эти примеры не могут сделать, это дать вам определение этой функции, которую вы могли бы скомпилировать. Если мы используем

int & foo()
{
    static int bar = 0;
    return bar;
}

Теперь у нас есть функция, которая возвращает ссылку на bar. поскольку bar static, он будет работать после вызова функции, поэтому возвращение ссылки на нее безопасно. Теперь, если мы делаем

foo() = 42;

Что происходит, мы назначаем 42 в bar, поскольку мы назначаем ссылку, а ссылка - это просто псевдоним для bar. Если мы снова назовем эту функцию, как

std::cout << foo();

Он будет печатать 42, так как мы установили bar выше.

Ответ 4

int &foo(); объявляет функцию с именем foo() с типом возврата int&. Если вы вызываете эту функцию без предоставления тела, вы, скорее всего, получите опорную ошибку undefined.

Во второй попытке вы предоставили функцию int foo(). Это имеет другой тип возврата к функции, объявленной int& foo();. Таким образом, у вас есть два объявления одного и того же foo, которые не совпадают, что нарушает правило одного определения, вызывающее поведение undefined (не требуется диагностика).

Для того, что работает, выньте объявление локальной функции. Они могут привести к тишине undefined, как вы видели. Вместо этого используйте только объявления функций вне любой функции. Ваша программа может выглядеть так:

int &foo()
{
    static int i = 2;
    return i;
}  

int main()
{
    ++foo();  
    std::cout << foo() << '\n';
}

Ответ 5

int& foo(); - это функция, возвращающая ссылку на int. Ваша предоставленная функция возвращает int без ссылки.

Вы можете сделать

int& foo()
{
    static int i = 42;
    return i;
}

int main()
{
    int& foo();
    foo() = 42;
}

Ответ 6

int & foo(); означает, что foo() возвращает ссылку на переменную.

Рассмотрим этот код:

#include <iostream>
int k = 0;

int &foo()
{
    return k;
}

int main(int argc,char **argv)
{
    k = 4;
    foo() = 5;
    std::cout << "k=" << k << "\n";
    return 0;
}

Этот код печатает:

$./a.out  к = 5

Потому что foo() возвращает ссылку на глобальную переменную k.

В вашем обновленном коде вы возвращаете возвращаемое значение в ссылку, которая затем недействительна.

Ответ 7

В этом контексте и означает ссылку - поэтому foo возвращает ссылку на int, а не int.

Я не уверен, если бы вы работали с указателями, но это похоже на идею, вы фактически не возвращаете значение из функции - вместо этого вы передаете информацию, необходимую для поиска местоположения в где это int.

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

Если вам интересно - причина, по которой вы получаете segfault, состоит в том, что вы возвращаете числовой литерал "2" - так это точная ошибка, которую вы получите, если бы вы определили const int, а затем попробуйте для изменения его значения.

Если вы еще не узнали о указателях и динамической памяти, тогда я бы порекомендовал это сначала, поскольку есть несколько понятий, которые, как мне кажется, трудно понять, если вы не изучаете их всех сразу.

Ответ 8

Пример кода на связанной странице - это просто объявление фиктивной функции. Он не компилируется, но если у вас определенная функция определена, она будет работать в целом. Пример означает "Если у вас была функция с этой сигнатурой, вы можете использовать ее так".

В вашем примере foo явно возвращает lvalue на основе подписи, но вы возвращаете rvalue, которое преобразуется в lvalue. Это, очевидно, решительно терпит неудачу. Вы можете сделать:

int& foo()
{
    static int x;
    return x;
}

и будет успешным, изменив значение x, сказав:

foo() = 10;

Ответ 9

У вас есть функция foo(), которая возвращает ссылку на целое число.

Итак, скажем, первоначально foo вернул 5, а позже, в вашей основной функции, вы скажете foo() = 10;, затем распечатайте foo, он напечатает 10 вместо 5.

Надеюсь, это имеет смысл:)

Я тоже новичок в программировании. Интересно видеть такие вопросы, которые заставляют вас думать!:)