19

Let

int a = 0;

Then is (int)a an rvalue in standard C++?

Different compilers show different results for this code:

#include <iostream>
using namespace std;

void f(int& x)
{
    cout << "l value" << endl;
}

void f(int&& x)
{
    cout << "r value" << endl;
}

int main()
{
    int a = 0;
    f((int)a);
}

compilers with different results:

1) http://cpp.sh/2r6

2) http://webcompiler.cloudapp.net/

M.M
  • 138,810
  • 21
  • 208
  • 365
Minimus Heximus
  • 2,683
  • 3
  • 25
  • 50
  • Has anyone checked to see if there is a [connect](http://connect.microsoft.com) bug yet? A cursory search did not turn one up. – Mgetz Oct 22 '14 at 13:53
  • @Mgetz I was looking, I have not found anything obvious though. – Shafik Yaghmour Oct 22 '14 at 13:56
  • [Filed as a defect on connect](https://connect.microsoft.com/VisualStudio/feedback/details/1008261) against VS2013 using @ShafikYaghmour's test case – Mgetz Oct 22 '14 at 14:00
  • 1
    It's a long-standing "feature" of MSVC that a temporary is allowed to bind to a non-const reference. Turn it off with [`/Za`](http://msdn.microsoft.com/en-us/library/0k0w269d.aspx) option. – Igor Tandetnik Oct 22 '14 at 14:03
  • @IgorTandetnik well it's filed as a bug now, MS can decide to keep or remove that extension at their discretion. However their compiler is non-conforming if they leave it enabled by default. – Mgetz Oct 22 '14 at 14:05
  • [Similar thread from yesterday](http://stackoverflow.com/questions/26480413/how-to-copy-from-primitive-type-variables-when-passing-through-rvalue-reference/26481317#26481317) – M.M Oct 23 '14 at 02:39
  • note: removed the language-lawyer tag as no lawyering is required , it's black and white; and added "visual-c++" and "lvalue" tag as I'm sure the same issue is responsible for a lot of other thigns. – M.M Oct 23 '14 at 05:09
  • 3
    MS has finally responded, this is apparently controlled by [/Zc:rvalueCast (Enforce type conversion rules)](http://msdn.microsoft.com/en-us/library/dn449507.aspx) they have marked my bug as fixed. I'm still seeking clarification on if this will be turned on by default in the future. – Mgetz Nov 08 '14 at 14:02

3 Answers3

12

The should be an rvalue but webcompiler is running Visual Studio and Visual Studio has an extension which allows temporary objects to be bound to non-const lvalue references. a bug/extension that casues it to generate an lvalue in this case As Igor points out above this can be disabled using /Za (see it live).

We can see that it should be an rvalue(specifically a prvalue) from the draft C++ standard section 5.4 Explicit type conversion (cast notation) paragraph 1 which says (emphasis mine):

The result of the expression (T) cast-expression is of type T. The result is an lvalue if T is an lvalue reference type or an rvalue reference to function type and an xvalue if T is an rvalue reference to object type; otherwise the result is a prvalue.[ Note: if T is a non-class type that is cv-qualified, the cv-qualifiers are ignored when determining the type of the resulting prvalue; see 3.10. —end note ]

Both gcc and clang result in rvalue which is the expected result.

As an aside, I would recommend using rextester over webcompiler since rextester allows you to share your program and also has live sharing.

Update

Ben Voigt point out this bug report and so it seems that Visual Studio actually produces an lvalue. So this is not simply a case of the extension which allows temporary objects to be bound to non-const lvalue references.

As dyp points out gcc used to have a cast to lvalue extension as well.

Update 2

Mgetz filed a bug report, the response was that this is fixed by using the /Zc:rvalueCast flag, the description of the flag is as follows:

When the /Zc:rvalueCast option is specified, the compiler correctly identifies an rvalue reference type as the result of a cast operation in accordance with the C++11 standard. When the option is not specified, the compiler behavior is the same as in Visual Studio 2012. By default, /Zc:rvalueCast is off. For conformance and to eliminate errors in the use of casts, we recommend that you use /Zc:rvalueCast.

It is unclear whether this flag will be enabled by default in future versions.

Community
  • 1
  • 1
Shafik Yaghmour
  • 154,301
  • 39
  • 440
  • 740
  • +1 for your recommendation. how long does the live sharing link lives? – Minimus Heximus Oct 23 '14 at 01:52
  • @MinimusHeximus not sure, I have only used for short periods and th site does not document it. – Shafik Yaghmour Oct 23 '14 at 02:08
  • This answer is wrong, actually. Visual C++ isn't using the misfeature that binds an lvalue reference to a temporary.... it is completely failing to create a temporary at all. See Matt's answer and my bug report https://connect.microsoft.com/VisualStudio/Feedback/Details/615622 – Ben Voigt Oct 23 '14 at 03:03
  • @BenVoigt thank you for sharing that link, it is odd though that using `/Za` fixes it so this no longer seems to be the default behavior and in fact when I use `/Za` this `(int)a = 2 ;` is an error. I will add your reference to my answer. – Shafik Yaghmour Oct 23 '14 at 09:24
  • 1
    The language extension that binds an rvalue to an lvalue-reference only works if there *is* an object; that's not true for prvalues of fundamental types http://rextester.com/TOJWJL48414. Strangely, gcc once had a similar "extension" that allowed the result of a cast to be used as an lvalue: https://gcc.gnu.org/gcc-3.4/changes.html (cast-as-lvalue) – dyp Oct 23 '14 at 09:50
  • @dyp that is odd, do you know what the use case for this is? – Shafik Yaghmour Oct 23 '14 at 13:17
  • @ShafikYaghmour For the MSVC or the GCC extension? – dyp Oct 23 '14 at 13:22
  • @dyp for casting to an lvalue which `gcc` used to have and `MSVC` still does. – Shafik Yaghmour Oct 23 '14 at 13:23
  • 1
    I can only hypothesize that `(char) i = 5;` is more convenient to write than `*((char*)&i) = 5;` (in C). You can find some discussion when searching for "cast-as-lvalue". E.g. it seems to have been in early C89 drafts. – dyp Oct 23 '14 at 13:24
  • @BenVoigt hmm maybe they'll finally fix it with my bug report. – Mgetz Oct 24 '14 at 12:36
  • @Mgetz if you let me know when you receive an update, I will also update my answer. – Shafik Yaghmour Oct 24 '14 at 12:37
  • @ShafikYaghmour MS has resolved the bug as fixed, apparently we were all wrong: [/Zc:rvalueCast (Enforce type conversion rules)](http://msdn.microsoft.com/en-us/library/dn449507.aspx) – Mgetz Nov 08 '14 at 14:00
5

Yes, the result of a cast to an object type is an rvalue, as specified by C++11 5.4/1:

The result is an lvalue if T is an lvalue reference type or an rvalue reference to function type and an xvalue if T is an rvalue reference to object type; otherwise the result is a prvalue.

Mike Seymour
  • 249,747
  • 28
  • 448
  • 644
5

In Standard C++ int(a) and (int)a are rvalues (the other answers provide standard references).

Your code example is exploiting a bug/extension in MSVC, but not what it seems like at first glance. As we can see from this code which works in MSVC:

#include <iostream>

int main()
{
    int x = 0;
    (int)x = 1;
    std::cout << x << std::endl;
}

MSVC treats (int)x as an lvalue.

Even though MSVC has an extension to allow rvalues to bind to non-const references; that extension still makes rvalue references a better match than lvalue references for rvalues.

M.M
  • 138,810
  • 21
  • 208
  • 365
  • 1
    I reported this and several other variants on Connect four years ago: https://connect.microsoft.com/VisualStudio/Feedback/Details/615622 – Ben Voigt Oct 23 '14 at 02:58