Что означает "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.
Надеюсь, это имеет смысл:)
Я тоже новичок в программировании. Интересно видеть такие вопросы, которые заставляют вас думать!:)