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



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



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


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



int foo()
{
return 2;
}

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


он компилируется нормально, но работает она дает ошибка сегментирования. Только строчка



int& foo();


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



что означает этот код? Как можно назначить значение для вызова функции, и почему это не rvalue?

1274   9  

9 ответов:

объяснение предполагает, что существует некоторая разумная реализация для 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
}

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

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. Это некоторый код, который может действительно служить цели, в отличие от других примеров.

int& foo();

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

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

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

foo() = 42;

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

std::cout << foo();

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

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

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

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

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

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

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

вы можете

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

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

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;
}

печатается код:

$ ./а.из k=5

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

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

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

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

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

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

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

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

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

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

и преуспел бы, изменив значение x, сказав:

foo() = 10;

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

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

Я надеюсь, что имеет смысл :)

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

Comments

    Ничего не найдено.