为什么左值引用和右值引用都可以绑定到函数?

huangapple go评论63阅读模式
英文:

Why can both lvalue references and rvalue references bind to functions?

问题

以下是代码部分的翻译:

using flref = int(&)(double);
using frref = int(&&)(double);
int foo(double){ return 32; }
int main(){
    flref l = foo;  // 函数左值引用绑定到函数名
    frref r = foo;  // 函数右值引用绑定到函数名
    return 0;
}

在这种情况下,为什么左值引用和右值引用都可以绑定到函数呢?GCC、Clang和MSVC都能够编译这段代码而没有错误。

当函数名用作表达式时,它是左值还是右值?在flref l = foo;这句中,=的右侧是一个表达式吗?

英文:

Consider following code:

using flref = int(&)(double);
using frref = int(&&)(double);
int foo(double){ return 32; }
int main(){
    flref l = foo;  // Function lvalue references are bound to the function name
    frref r = foo;  // Function rvalue references are bound to the function name
    return 0;
}

Why can both the lvalue reference and the rvalue reference bind to the function in this case? Both GCC, Clang, and MSVC compile this code without errors.

Is a function name an lvalue or an rvalue when used as an expression?

In the flref l = foo; sentence, is the rhs of = an expression?

答案1

得分: 4

  • 函数名作为表达式时,该函数名是左值还是右值?

  • 一个指代函数的 id-expression 是该函数类型的左值表达式。没有函数类型的右值表达式。

  • 为什么函数名可以绑定到左值引用和右值引用?

  • 因为函数类型的左值表达式特别豁免了对右值引用必须通过右值(具体为 xvalue)表达式初始化的要求,即使在潜在的临时材料化之后也是如此。请参见 [dcl.init.ref]/5.3.1 中的 "or function"。

  • 之所以选择这种方式进行规定,可能是因为这是最方便的选择。其他的选择要么是完全禁止将函数绑定到右值引用,这会使得通用代码写起来更加困难,要么就是引入函数右值的概念,这样只会迫使每个人在函数名周围一直写 std::move

  • 在这个句子中,等号右侧是一个表达式吗?

  • 它被称为一个 "语句",而不是一个 "句子"。在变量初始化的等号右侧,必须是一个 "braced-init-list"(即 = { /*...*/ })或者一个 "表达式"。如果没有花括号,那么它只能是一个表达式。

英文:

> Whether the function name is a lvalue or an rvalue when used as an expression?

An id-expression naming a function is an lvalue expression of the function's type. There are no rvalue expressions with function type.

> Why can both function left and right references be bound to function names?

Because lvalue expressions of function type are specifically exempt from the requirement that a rvalue reference must be initialized, after potential temporary materialization, by an rvalue (specifically xvalue) expression. See "or function" in [dcl.init.ref]/5.3.1.

This was probably chosen to be specified this way since it is the most convenient choice. The alternatives would be either to disallow rvalue references to functions completely, which would make generic code unnecessarily more difficult to write or to introduce a notion of function rvalues, which would just force everyone to write std::move around function names all the time.

> flref l = foo; In this sentence, is the right side of the equal sign an expression?

It is called a statement, not a sentence. The right-hand side of the equals sign in a variable initializer must always be either a braced-init-list (i.e. = { /*...*/ }) or an expression. If there are no braces, then it can't be anything but an expression.


As an aside: Calling a "lvalue reference" a "left reference" and a "rvalue reference" a "right reference" is very misleading. The pre-C++ origin of the terms "lvalue" and "rvalue" might be related to "left" and "right" side of assignment, but that meaning is only applicable in a small subset of the C++ language.

huangapple
  • 本文由 发表于 2023年4月17日 11:26:39
  • 转载请务必保留本文链接:https://go.coder-hub.com/76031528.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定