Error returning type reference with expression: `cond? * this: throw () `

This seems like a mistake, but I just want to confirm. Are the following well formed? If not, why not?

#include <iostream> struct X { int value; constexpr X(int value) : value(value) {} constexpr X& do_something(int x) { return x < 3 ? *this : throw("FAIL"); //return *this; } }; int main() { X x(2); std::cout << x.do_something(1).value << std::endl; } 

In VC++2015 R3 with default solution switches, I get:

 warning C4172: returning address of local variable or temporary 

g++ (GCC) 5.4.0 using the -Wall -pedantic I get:

 error: invalid initialization of non-const reference of type 'X&' from an rvalue of type 'X' return x < 3 ? *this : throw("FAIL"); ^ 

However, clang version 3.9.1 (tags/RELEASE_391/final) with -Wall -pedantic switches has no problems with it.

Using a return *this; Of course, no problem.

+7
c ++ visual-c ++ g ++ clang ++ c ++ 14
source share
3 answers

Since you have a C ++ 14 tag, the code is 100% well-formed C ++ 14.

The main problem of 1560 removed the free lvalue-to-rval conversion here, and as a resolution of the defect report, it should eventually be applied to completely return to C ++ 98/03 compiler mode, offering such a mode.

See also GCC Error 64372 .

+10
source share

C ++ 11 15/2 says:

A try-block is a statement (Clause 6). A throw-expression is of type void...

Then 5.16 / 2: (from the question that @Fred Larson Mjollnir'd, and then not reset)

If either the second or third operand is of type void, then lvalue-to-rvalue (4.1), from the array to the pointer (4.2) and the standard conversion of the to-pointer function (4.3) is performed on the second and third operands, and one of the following values:

- the second or third operand (but not both) is a throw expression (15.1); the result is of the other type and is prvalue.

- both the second and third operands are invalid; the result is of type void and is prvalue.

So, from this we see that the conditional expression operator (ternary) is legal. But the result ?: Is a prvalue, which then cannot be legally associated with a non-constant X& return type and is actually poorly formed.

+3
source share

Why not use something that doesn't forget to work, and is easier to read? For example:

 X& do_something(int x) { if (x >= 3) throw("FAIL"); return *this; } 

I am not an expert on compilers, but I think the example you posted will work if the compiler handles this particular case of an angle. As I read this, your do_something(int x) function expands to this:

 X& do_something(int x) { if x < 3 return *this; else return throw("FAIL"); } 

Now throw is a keyword and, as such, has no return value, therefore, strictly speaking, this is a compile-time error. However, I think the compilers (or at least some of them) are kind enough to go: "Oh, good ... There is no return value, but throw is a special situation that will cause the function to not return anyway, so don’t let complain and let the exception handling at runtime. "

I personally do not like to take my chances with compilers and try to keep everything as good as possible, but ... although this may be the best practice, it can also be just a personal preference.

+2
source share

All Articles