I was filing a GCC bug for this, but I'd rather double-check this.
Consider the following programs:
#include <utility>
template<typename T, typename A>
void F(A&& a) { T(std::forward<A>(a)); } // Note: () syntax.
int main() { int i; F<int&>(i); }
and:
#include <utility>
template<typename T, typename A>
void F(A&& a) { T{std::forward<A>(a)}; } // Note: {} syntax.
int main() { int i; F<int&>(i); }
Latest Clang and MSVC compilers accept both programs. GCC 5 and beyond accept the first program but reject the second, claiming invalid cast of an rvalue expression of type 'int' to type 'int&'
.
Is this a GCC bug? Or is this indeed a difference between T{}
and T()
in the above context (and thus a bug in Clang and MSVC)?
Edit:
The issue can be narrowed down to the following simpler excerpts:
int i; (int&){i};
and
int i; (int&)(i);
If a type has a default constructor, either implicitly or explicitly declared, you can use brace initialization with empty braces to invoke it. For example, the following class may be initialized by using both empty and non-empty brace initialization: C++ Copy.
Different programming languages have various ways to delineate the start and end points of a programming structure, such as a loop, method or conditional statement. For example, Java and C++ are often referred to as curly brace languages because curly braces are used to define the start and end of a code block.
Uniform initialization is a feature in C++ 11 that allows the usage of a consistent syntax to initialize variables and objects ranging from primitive type to aggregates. In other words, it introduces brace-initialization that uses braces ({}) to enclose initializer values.
In programming, curly braces (the { and } characters) are used in a variety of ways. In C/C++, they are used to signify the start and end of a series of statements. In the following expression, everything between the { and } are executed if the variable mouseDOWNinText is true. See event loop.
There are two separate issues:
T{x}
should do for reference type T
. Currently [expr.type.conv]/1 says that it creates a prvalue of type T
, which is nonsense for reference types. This is core issue 1521.T{x}
for reference type T
do roughly T __tmp{x};
and then yield the equivalent of static_cast<T>(__tmp)
(so xvalue for rvalue reference T
and lvalue for lvalue reference T
). However, C++11 as published screwed up the specification for list-initialization of references, making it always create a temporary. The result was that int i; int &r{i};
failed to compile because it would attempt to bind r
to a temporary copy of i
, which is obviously nonsense. This is fixed by core issue 1288, whose resolution GCC is supposed to implement, but it looks like from the error message that it's not completely fixed.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