Is the following code legal (by C++11 and/or C++14 standard(s))?
#include <iostream>
#include <utility>
using namespace std;
void foo(int &a) {
cout << a << endl;
}
int main() {
foo(reinterpret_cast<int &>(move(5)));
}
a
inside foo
without it becoming UB?It compiles on clang 3.5, not on gcc 4.9. GCC error:
➤ g++-4.9 -std=c++1y sample.cpp -o sample
sample.cpp: In function 'int main()':
sample.cpp:11:40: error: invalid cast of an rvalue expression of type 'std::remove_reference<int>::type {aka int}' to type 'int&'
foo(reinterpret_cast<int &>(move(5)));
^
FYI, a custom made cast that's less hairy than the previous, and which works on C++11 for both GCC and Clang, would be the following lvalue
function:
#include <iostream>
namespace non_std {
template <typename T>
constexpr T &lvalue(T &&r) noexcept { return r; }
}
void divs(int &a, int &b) {
int t = a;
a /= b;
b /= t;
}
int main() {
using namespace std;
using namespace non_std;
int i_care_for_this_one = 4;
divs(i_care_for_this_one, lvalue(2));
cout << i_care_for_this_one << endl;
}
Purpose for using reinterpret_cast It is used when we want to work with bits. If we use this type of cast then it becomes a non-portable product. So, it is suggested not to use this concept unless required. It is only used to typecast any pointer to its original type.
The reinterpret_cast allows the pointer to be treated as an integral type. The result is then bit-shifted and XORed with itself to produce a unique index (unique to a high degree of probability). The index is then truncated by a standard C-style cast to the return type of the function.
the result of a pointer-to-pointer reinterpret_cast operation can't safely be used for anything other than being cast back to the original pointer type.
Update: The code is ill-formed in C++11. Answer below is for C++14. See note at the end of this answer.
I believe this code is both well-formed and well-defined. Here's why.
The result of std::move
is an xvalue [1], which is a type of glvalue; and converting a glvalue to an lvalue reference with reinterpret_cast
appears to be allowed by the wording of the standard:
A glvalue expression of type
T1
can be cast to the type “reference toT2
” if an expression of type “pointer toT1
” can be explicitly converted to the type “pointer toT2
” using areinterpret_cast
. The result refers to the same object as the source glvalue, but with the specified type. [ Note: That is, for lvalues, a reference castreinterpret_cast<T&>(x)
has the same effect as the conversion*reinterpret_cast<T*>(&x)
with the built-in&
and*
operators (and similarly forreinterpret_cast<T&&>(x)
). — end note ] No temporary is created, no copy is made, and constructors (12.1) or conversion functions (12.3) are not called.73
Since "pointer to int
" can be converted to "pointer to int
", this reinterpret_cast
is also allowed. The standard doesn't say anything about whether the destination type has to be an lvalue reference or rvalue reference.
The result of the cast is well-defined by the paragraph above: it refers to the same object as the source glvalue---that is, a temporary int
object with the value 5
. ([dcl.init.ref] specifies that a temporary is created when a prvalue is bound to a reference.)
Accessing the value through the int&
also doesn't violate any aliasing rules since the original object was also of type int
. In fact I believe it would even be well-defined to modify the temporary through the lvalue thus obtained.
Note: The C++11 wording says "lvalue expression", not "glvalue expression". The wording with "glvalue expression" is from N3936, which is the final working draft for C++14. I'm not an expert in how the standardization process works, but I believe this means that the change of "lvalue" to "glvalue" was already voted in by the committee, and when ISO publishes the C++14 standard, it's going to be pretty similar to what it says above.
[1] Except in the rare case in which the argument is a function; in that case the result is an lvalue, since there are no function rvalues.
The issue turns on whether reinterpret_cast is allowed to convert xvalues to lvalues. Contrary to what others are pasting, the relevant paragraph (5.2.10.11) only mentions lvalues:
An lvalue expression of type T1 can be cast to the type “reference to T2” if an expression of type “pointer to T1” can be explicitly converted to the type “pointer to T2” using a reinterpret_cast..
There is a proposal submitted by Michael Wong to change the wording to glvalue, but it appears to have hit a wall:
http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1268
I take it that this means, as of now, the conversion is not legal, since it only explicitly allows the conversion from lvalues.
The relevant section in the standard is 5.2.10 [expr.reinterpret.cast]. There are two relevant paragraphs:
First, there is paragraph 1 which ends in:
No other conversion can be performed explicitly using reinterpret_cast.
... and paragraph 11 as none of the other apply:
A glvalue expression of type
T1
can be cast to the type “reference toT2
” if an expression of type “pointer toT1
” can be explicitly converted to the type “pointer toT2
” using areinterpret_cast
. The result refers to the same object as the source glvalue, but with the specified type. [ Note: That is, for lvalues, a reference castreinterpret_cast<T&>(x)
has the same effect as the conversion*reinterpret_cast<T*>(&x)
with the built-in&
and*
operators (and similarly forreinterpret_cast<T&&>(x))
. —end note ] No temporary is created, no copy is made, and constructors (12.1) or conversion functions (12.3) are not called.
All the other clauses don't apply to objects but only to pointers, pointers to functions, etc. Since an rvalue is not a glvalue, the code is illegal.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With