yohhoyの日記

技術的メモをしていきたい日記

関数型の右辺値は存在しない

プログラミング言語C++に「関数型(function type)の右辺値(rvalue)」は存在しない。関数型をもつ式の value category は常に左辺値(lvalue)となる。だから何?

int v;
struct S s;
void f();

std::move(v);  // xvalue
std::move(s);  // xvalue
std::move(f);  // lvalue

static_cast<void(&)()>(f);   // lvalue
static_cast<void(&&)()>(f);  // lvalue
static_cast<void(*)()>(f);   // prvalue(関数ポインタ型)
void g(void(&)());   // #1
void g(void(&&)());  // #2

g(f);  // #1を呼び出す
g(std::move(f)); // #1を呼び出す

別途 Function-to-pointer 変換によって、関数型の lvalue は関数ポインタ型の prvalue へと変換されうる。*1

C++17 7/p6, 8.2.2/p11 より引用(下線部は強調)。*2

The effect of any implicit conversion is the same as performing the corresponding declaration and initialization and then using the temporary variable as the result of the conversion. The result is an lvalue if T is an lvalue reference type or an rvalue reference to function type (11.3.2), an xvalue if T is an rvalue reference to object type, and a prvalue otherwise. The expression e is used as a glvalue if and only if the initialization uses it as a glvalue.

A function call is an lvalue if the result type is an lvalue reference type or an rvalue reference to function type, an xvalue if the result type is an rvalue reference to object type, and a prvalue otherwise.

C++11に右辺値参照が追加されたとき、新しい概念の導入による複雑化を避けるため特別扱いされた。(PDF)N3055 Background より一部引用。

In addition, rvalue references (like traditional lvalue references) can be bound to functions. Treating an rvalue reference return value as an rvalue, however, introduces the novel concept of a function rvalue into the language. There was previously no such idea -- a function lvalue used in an rvalue context becomes a pointer-to-function rvalue, not a function rvalue -- so the current draft Standard does not describe how such rvalues are to be treated. In particular, function calls and conversions to function pointers are specified in terms of function lvalues, so most plausible uses of rvalue references to functions are undefined in the current wording.

関連URL

*1:C++17 7.3/p1: "An lvalue of function type T can be converted to a prvalue of type "pointer to T". The result is a pointer to the function."

*2:static_cast式, reinterpret_cast式, キャスト式でも rvalue reference to function type へのキャスト結果は lvalue と定義されている(8.2.9/p1, 8.2.10/p1, 8.4/p1)