ChatGPT解决这个技术问题 Extra ChatGPT

“int& foo()”在 C++ 中是什么意思?

在阅读有关左值和右值的 this explanation 时,这些代码行让我印象深刻:

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

我在 g++ 中尝试过,但编译器说“未定义对 foo() 的引用”。如果我添加

int foo()
{
  return 2;
}

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

它编译得很好,但运行它会得到一个 segmentation fault。只是线

int& foo();

本身编译和运行都没有任何问题。

这段代码是什么意思?如何为函数调用赋值,为什么它不是右值?

您不是为函数调用赋值,而是为它返回的引用赋值。
@FrédéricHamidi 为返回的引用所指的对象赋值
是的,它是对象的别名;引用不是对象
@RoyFalk 本地函数声明是一个问题,我个人很高兴看到它们从语言中删除。 (当然不包括 lambdas)
已经有一个 GCC bug for this

T
TartanLlama

解释是假设 foo 有一些合理的实现,它返回对有效 int 的左值引用。

这样的实现可能是:

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

int& foo() {
    return a;
} 

现在,由于 foo 返回一个左值引用,我们可以为返回值分配一些东西,如下所示:

foo() = 42;

这将使用值 42 更新全局 a,我们可以通过直接访问变量或再次调用 foo 来检查:

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

在 operator[] 中合理吗?或者其他一些成员访问方法?
鉴于对引用的混淆,最好从样本中删除静态局部变量。初始化增加了不必要的复杂性,这是学习的障碍。让它成为一个全球性的。
K
Kate Gregory

所有其他答案都在函数内部声明了一个静态。我认为这可能会使您感到困惑,因此请看一下:

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 a{3} 而不是 int a = 3?这种语法对我来说似乎不合适。
@AlexPetrenko 这是通用初始化。我碰巧在我方便的示例中使用了它。没有什么不合适的
我知道这是什么。 a = 3 感觉干净多了。个人喜好)
就像在函数中声明 static 可能会使某些人感到困惑一样,我也相信使用通用初始化也是可能的。
@AlekseiPetrenko 在 int a = 1.3 的情况下,它会隐式转换为 a = 1。而 int a {1.3} 会导致错误:缩小转换。
N
NathanOliver
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 设置为上面的值。


M
M.M

int &foo(); 声明了一个名为 foo() 的函数,其返回类型为 int&。如果您在没有提供主体的情况下调用此函数,那么您可能会收到未定义的引用错误。

在您的第二次尝试中,您提供了一个函数 int foo()。这与 int& foo(); 声明的函数具有不同的返回类型。因此,您有两个不匹配的相同 foo 声明,这违反了导致未定义行为的单一定义规则(无需诊断)。

对于有效的东西,取出局部函数声明。如您所见,它们可能导致无声的未定义行为。相反,只在任何函数之外使用函数声明。您的程序可能如下所示:

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

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

P
Peter Mortensen

int& foo(); 是返回对 int 的引用的函数。您提供的函数返回 int 而不参考。

你可以做

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

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

v
vy32

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 k=5

因为 foo() 返回对全局变量 k 的引用。

在您修改后的代码中,您将返回的值转换为引用,然后该引用无效。


B
Brett

在这种情况下,& 表示引用 - 所以 foo 返回对 int 的引用,而不是 int。

我不确定您是否已经使用过指针,但这是一个类似的想法,您实际上并没有从函数中返回值 - 相反,您传递的是在内存中找到该位置所需的信息国际群岛

因此,总而言之,您并没有为函数调用分配值-您正在使用函数来获取引用,然后将被引用的值分配给新值。很容易认为所有事情都同时发生,但实际上计算机以精确的顺序完成所有事情。

如果你想知道 - 你得到一个段错误的原因是因为你返回一个数字文字 '2' - 所以如果你定义一个 const int 然后尝试修改它,这就是你得到的确切错误价值。

如果您还没有了解指针和动态内存,那么我建议您首先了解一些我认为很难理解的概念,除非您同时学习它们。


P
Peter Mortensen

链接页面上的示例代码只是一个虚拟函数声明。它不能编译,但如果你定义了一些函数,它通常可以工作。这个例子的意思是“如果你有一个带有这个签名的函数,你可以这样使用它”。

在您的示例中,foo 显然是根据签名返回一个左值,但您返回一个转换为左值的右值。这显然是注定要失败的。你可以这样做:

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

并且会通过改变 x 的值来成功,当说:

foo() = 10;

P
Peter Mortensen

您拥有的函数 foo() 是一个返回对整数的引用的函数。

所以假设最初 foo 返回 5,然后在你的 main 函数中,你说 foo() = 10;,然后打印出 foo,它将打印 10 而不是 5。

我希望这是有道理的 :)

我也是编程新手。看到这样让你思考的问题很有趣! :)