简体   繁体   中英

What's the type of the function call expression?

This is a language lawyer question. Clause 5p5 in C++11 reads:

If an expression initially has the type “reference to T” (8.3.2, 8.5.3), the type is adjusted to T prior to any further analysis. The expression designates the object or function denoted by the reference, and the expression is an lvalue or an xvalue, depending on the expression.

On the other hand, §5.2.2p3 states:

If the postfix-expression designates a destructor (12.4), the type of the function call expression is void; otherwise, the type of the function call expression is the return type of the statically chosen function (ie, ignoring the virtual keyword), even if the type of the function actually called is different. This type shall be an object type, a reference type or the type void.

Consider this piece of code:

int& f();
f();  // What is the type of this expression?

This was corrected post publication of the standard, in DR 1261 . Draft n3485 reads:

[...] otherwise, the type of the function call expression is the return type of the statically chosen function (ie, ignoring the virtual keyword), even if the type of the function actually called is different. This return type shall be an object type, a reference type or cv void .

(my emphasis; not in your quote).

The two paragraphs are now compatible; the (initial) type of the function call expression is now int & , which gets adjusted to int and value-category lvalue immediately. A similar process occurs with a function returning a qualified type, which has the advantage that we don't need to worry about lvalue-to-reference conversion:

const int g();
static_assert(std::is_same<decltype(g()), int>::value, "!!!");

The type of f() is int ; its value category is lvalue. You can demonstrate this fact:

int& f();
static_assert(std::is_same<int&,decltype((f()))>::value,"EXPLODE");

per C++11 §7.1.6.2 [dcl.type.simple]/4 "...if e is an lvalue, decltype(e) is T& , where T is the type of e ".

Example code:

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

template< class Type >
struct Is_ref_ { static const bool yes = false; };

template< class Type >
struct Is_ref_<Type&> { static const bool yes = true; };

#include <iostream>
using namespace std;
auto main() -> int
{
    cout << boolalpha;
    cout << "Function calls foo versus bar:" << endl;
    cout << Is_ref_<decltype(foo())>::yes << endl;
    cout << Is_ref_<decltype(bar())>::yes << endl;

    int a;
    int& b = a;
    cout << endl;
    cout << "lvalue versus ref:" << endl;
    cout << Is_ref_<decltype(a)>::yes << endl;
    cout << Is_ref_<decltype(b)>::yes << endl;
}

Output with Visual C++ 12.0 and with MinGW g++ 4.7.2:

Function calls foo versus bar:
true
false

lvalue versus ref:
false
true

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM