简体   繁体   中英

Why return-type 'cv' is ignored?

At least in 'Clang' & 'GCC'. Here is an example:

char *const InString(char *const p) {

    return gets(p);
}

int main()
{
    static char arr[260];

    char * &&str = InString(arr); //compiles without error - what??????
}

As most of you probably knows in the second line of ' main' we are bounding the return-value temporary ('prvalue') into an 'rvalue reference' thus extending its life time. So my question is what is happening here - is 'cv' for return-values really ignored and if so where in the standard this is written or else how 'char *const &&' is converted to 'char * &&' ?

*Need ISO C++ standard qualification.

EDIT: The thing is that before 'C++ 11' you weren't allowed to modify the return-value whatsoever because 'rvalues' weren't introduced and also because something like:

InString(arr) = nullptr;

Was meaningless. However now you can extend the 'return-value' life-time and so modifying it becomes possible:

auto &&refRetVal = InString(arr);

refRetVal = nullptr;

From this it comes that the 'const' return 'cv' can be useful. If the return-type of 'InString' above is 'constant' then the second assignment to 'nullptr' will be illegal.

After considering the quote mentioned by @dyp, which is [expr]/6:

If a prvalue initially has the type “ cv T ,” where T is a cv-unqualified non-class, non-array type, the type of the expression is adjusted to T prior to any further analysis .

The conclusion is rather simple: As the expression InString(..) is a prvalue, the type of InString(..) (which is the initializer of the reference) is simply adjusted to char* , which is clearly reference compatible to the target type of the reference (also char* ). In other words, the const you added is simply ignored when determining the type of the function call expression (but it is not ignored when looking at the function type itself!).

However, for scalar prvalues, references never bind directly to the initializer expression, but a temporary is initialized and the reference bound to it:

int&& i = 4; // Temporary initialized with 4 and bound to i

int const f();
int&& ref = f(); // Initializer expression has type int - same as above

The cv-qualifier in return types is ignored only of the very first level, so int const foo() equals int foo() but int const &foo() does not equal int &foo() .

In your case, your function char *const InString() is equivalent to char *InString() .

And about the binding of the char *&&str = InString(arr) . The return of the function is a r-value (a temporary), and str is an r-value reference, so this is expected. Of course, the lifetime of the temporary is extended to the scope of the reference.

BTW, your code, compiled with -Wextra gives in CLang++:

warning: 'const' type qualifier on return type has no effect [-Wignored-qualifiers]

And in G++:

warning: type qualifiers ignored on function return type [-Wignored-qualifiers]

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