As an answer to another question I wanted to post the following code (that is, I wanted to post code based on this idea):
#include <iostream>
#include <utility> // std::is_same, std::enable_if
using namespace std;
template< class Type >
struct Boxed
{
Type value;
template< class Arg >
Boxed(
Arg const& v,
typename enable_if< is_same< Type, Arg >::value, Arg >::type* = 0
)
: value( v )
{
wcout << "Generic!" << endl;
}
Boxed( Type&& v ): value( move( v ) )
{
wcout << "Rvalue!" << endl;
}
};
void function( Boxed< int > v ) {}
int main()
{
int i = 5;
function( i ); //<- this is acceptable
char c = 'a';
function( c ); //<- I would NOT like this to compile
}
However, while MSVC 11.0 chokes at the last call, as it IHMO should, MinGW g++ 4.7.1 just accepts it, and invokes the constructor with rvalue reference formal argument.
It looks to me as if an lvalue is bound to an rvalue reference. A glib answer could be that the lvalue is converted to rvalue. But the question is, is this a compiler bug, and if it’s not, how does the Holy Standard permit this?
EDIT: I managed to reduce it all to the following pretty short example:
void foo( double&& ) {}
int main()
{
char ch = '!';
foo( ch );
}
Fails to compile with MSVC 11.0, does compile with MinGW 4.7.1, which is right?
I haven't check the spec but I guess char can be automatically cast to int. Since you cannot assign anything (it's r-value) the R-value to temporary variable of type int (to be more explicit to (int)c value) will be passed.
I discovered that N3290 (identical to C++11 standard) contains non-normative example of binding double&& to rvalue generated from int lvalue, and the updated wording in §8.5.3
“If T1 is reference-related to T2 and the reference is an rvalue reference,
the initializer expression shall not be an lvalue.”
The rules were reportedly designed to avoid inefficient extra copying. Although I fail to see how such copying could not be optimized away. Anyway, whether the rationale is reasonable or not – and it certainly doesn't seem as a reasonable effect! – the following code is allowed, and compiles with both MSVC 11 and MinGW g++ 4.7:
struct Foo {};
struct Bar { Bar( Foo ) {} };
void ugh( Bar&& ) {}
int main()
{
Foo o;
ugh( o );
}
So apparently MSVC 11 is wrong in not permitting the lvalue -> rvalue conversion.
EDIT: I learned that there is Defect Report about this issue, DR 1414. The Feb 2012 conclusion was that the current behavior specification is “correct”, presumably with respect to how well it reflects the intention. It is however reportedly still discussed in the committee, presumably with respect to the practicality of the intention.
Presumably you agree this is valid?
void foo( double ) {} // pass-by-value
int main()
{
char ch = '!';
foo( ch );
}
There's an implicit conversion from char to double, so the function is viable.
It's the same in the example in your edited question, there's an implicit conversion that produces a temporary (i.e. an rvalue) and the rvalue-reference argument binds to that temporary. You can make that conversion explicit if you prefer:
void foo( double&& ) {} // pass-by-reference
int main()
{
char ch = '!';
foo( double(ch) );
}
but that doesn't really change anything in this case. That would be necessary if double -> char could only be converted explicitly (e.g. for class types with explicit constructors or explicit conversion operators) but double to char is a valid implicit conversion.
The "an rvalue-reference cannot bind to an lvalue" rule you're thinking of refers to binding a T&& to a T lvalue, and that rule isn't broken because the double&& doesn't bind to the char, it binds to a temporary created by the implicit conversion.
That rule doesn't only exist to prevent unnecessary extra copying, but to fix a real safety problem that existed with the previous rules, see http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2008/n2812.html
Edit: It was asked whether this behaviour is desirable on the committee reflector (see DR 1414) and it was decided that yes, this behaviour is intended and is correct. One of the arguments used to reach that position was that this code is more efficient with the current rules:
std::vector<std::string> v;
v.push_back("text");
With the current rules a temporary std::string is created by an implicit conversion, then std::vector<T>::push_back(T&&) is called, and the temporary is moved into the vector. If that push_back overload Wasn't viable for the result of a conversion then the code above would call std::vector<T>::push_back(const T&) which would cause a copy. The current rules make this real-world use case more efficient. If the rules said rvalue-refs cannot bind to the result of implicit conversions you would have to change the code above to get the efficiency of a move:
v.push_back( std::string{"text"} );
IMHO it makes no sense to have to explicitly construct a std::string when that constructor is not explicit. I want consistent behaviour from explicit/implicit constructors, and I want the first push_back example to be more efficient.
Related
This code
#include <iostream>
#include <optional>
struct foo
{
explicit operator std::optional<int>() {
return std::optional<int>( 1 );
}
explicit operator int() {
return 2;
}
};
int main()
{
foo my_foo;
std::optional<int> my_opt( my_foo );
std::cout << "constructor: " << my_opt.value() << std::endl;
my_opt = static_cast<std::optional<int>>(my_foo);
std::cout << "static_cast: " << my_opt.value() << std::endl;
}
produces the following output
constructor: 2
static_cast: 2
in Clang 4.0.0 and in MSVC 2017 (15.3). (Let's ignore GCC for now, since it's behavior seems to be buggy in that case.)
Why is the output 2? I would expect 1. The constructors of std::optional seem to prefer casting to the inner type (int) despite the fact that a cast to the outer type (std::optional<int>) is available. Is this correct according to the C++ standard? If so, is there a reason the standard does not dictate to prefer an attempt to cast to the outer type? I would find this more reasonable and could imagine it to be implemented using enable_if and is_convertible to disable the ctor if a conversion to the outer type is possible. Otherwise every cast operator to std::optional<T> in a user class - even though it is a perfect match - would be ignored on principle if there is also one to T. I would find this quite obnoxious.
I posted a somewhat similar question yesterday but probably did not state my problem accurately, since the resulting discussion was more about the GCC bug. That's why I am asking again more explicitly here.
In case Barry's excellent answer still isn't clear, here's my version, hope it helps.
The biggest question is why isn't the user-defined conversion to optional<int> preferred in direct initialization:
std::optional<int> my_opt(my_foo);
After all, there is a constructor optional<int>(optional<int>&&) and a user-defined conversion of my_foo to optional<int>.
The reason is the template<typename U> optional(U&&) constructor template, which is supposed to activate when T (int) is constructible from U and U is neither std::in_place_t nor optional<T>, and direct-initialize T from it. And so it does, stamping out optional(foo&).
The final generated optional<int> looks something like:
class optional<int> {
. . .
int value_;
. . .
optional(optional&& rhs);
optional(foo& rhs) : value_(rhs) {}
. . .
optional(optional&&) requires a user-defined conversion whereas optional(foo&) is an exact match for my_foo. So it wins, and direct-initializes int from my_foo. Only at this point is operator int() selected as a better match to initialize an int. The result thus becomes 2.
2) In case of my_opt = static_cast<std::optional<int>>(my_foo), although it sounds like "initialize my_opt as-if it was std::optional<int>", it actually means "create a temporary std::optional<int> from my_foo and move-assign from that" as described in [expr.static.cast]/4:
If T is a reference type, the effect is the same as performing the
declaration and initializationT t(e); for some invented temporary
variable t ([dcl.init]) and then using the temporary variable as the
result of the conversion. Otherwise, the result object is
direct-initialized from e.
So it becomes:
my_opt = std::optional<int>(my_foo);
And we're back to the previous situation; my_opt is subsequently initialized from a temporary optional, already holding a 2.
The issue of overloading on forwarding references is well-known. Scott Myers in his book Effective Modern C++ in Chapter 26 talks extensively about why it is a bad idea to overload on "universal references". Such templates will tirelessly stamp out whatever the type you throw at them, which will overshadow everything and anything that is not an exact match. So I'm surprised the committee chose this route.
As to the reason why it is like this, in the proposal N3793 and in the standard until Nov 15, 2016 it was indeed
optional(const T& v);
optional(T&& v);
But then as part of LWG defect 2451 it got changed to
template <class U = T> optional(U&& v);
With the following rationale:
Code such as the following is currently ill-formed (thanks to STL for
the compelling example):
optional<string> opt_str = "meow";
This is because it would require two user-defined conversions (from
const char* to string, and from string to optional<string>) where the
language permits only one. This is likely to be a surprise and an
inconvenience for users.
optional<T> should be implicitly convertible from any U that is
implicitly convertible to T. This can be implemented as a non-explicit
constructor template optional(U&&), which is enabled via SFINAE only
if is_convertible_v<U, T> and is_constructible_v<T, U>, plus any
additional conditions needed to avoid ambiguity with other
constructors...
In the end I think it's OK that T is ranked higher than optional<T>, after all it's a rather unusual choice between something that may have a value and the value.
Performance-wise it is also beneficial to initialize from T rather than from another optional<T>. An optional is typically implemented as:
template<typename T>
struct optional {
union
{
char dummy;
T value;
};
bool has_value;
};
So initializing it from optional<T>& would look something like
optional<T>::optional(const optional<T>& rhs) {
has_value = rhs.has_value;
if (has_value) {
value = rhs.value;
}
}
Whereas initializing from T& would require less steps:
optional<T>::optional(const T& t) {
value = t;
has_value = true;
}
A static_cast is valid if there is an implicit conversion sequence from the expression to the desired type, and the resulting object is direct-initialized from the expression. So writing:
my_opt = static_cast<std::optional<int>>(my_foo);
Follows the same steps as doing:
std::optional<int> __tmp(my_foo); // direct-initialize the resulting
// object from the expression
my_opt = std::move(__tmp); // the result of the cast is a prvalue, so move
And once we get to construction, we follow the same steps as my previous answer, enumerating the constructors, which ends up selecting the constructor template, which uses operator int().
I'm having trouble with std::functions created from lambdas if the function returns a reference but the return type isn't explicitly called out as a reference. It seems that the std::function is created fine with no warnings, but upon calling it, a value is returned when a reference is expected, causing things to blow up. Here's a very contrived example:
#include <iostream>
#include <vector>
#include <functional>
int main(){
std::vector<int> v;
v.push_back(123);
std::function<const std::vector<int>&(const std::vector<int>&)> callback =
[](const std::vector<int> &in){return in;};
std::cout << callback(v).at(0) << std::endl;
return 0;
}
This prints out garbage, however if the lambda is modified to explicitly return a const reference it works fine. I can understand the compiler thinking the lambda is return-by-value without the hint (when I originally ran into this problem, the lambda was directly returning the result from a function that returned a const reference, in which case I would think that the const reference return of the lambda would be deducible, but apparently not.) What I am surprised by is that the compiler lets the std::function be constructed from the lambda with mismatched return types. Is this behavior expected? Am I missing something in the standard that allows this mismatch to occur? I'm seeing this with g++ (GCC) 4.8.2, haven't tried it with anything else.
Thanks!
Why is it broken?
When the return type of a lambda is deduced, reference and cv-qualifications are dropped. So the return type of
[](const std::vector<int> &in){return in;};
is just std::vector<int>, not std::vector<int> const&. As a result, if we strip out the lambda and std::function part of your code, we effectively have:
std::vector<int> lambda(std::vector<int> const& in)
{
return in;
}
std::vector<int> const& callback(std::vector<int> const& in)
{
return lambda(in);
}
lambda returns a temporary. It effectively is just copied its input. This temporary is bound the reference return in callback. But temporaries bound to a reference in a return statement do not have their lifetime extended, so the temporary is destroyed at the end of the return statement. Thus, at this point:
callback(v).at(0)
-----------^
we have a dangling reference to a destroyed copy of v.
The solution is to explicitly specify the return type of the lambda to be a reference:
[](const std::vector<int> &in)-> const std::vector<int>& {return in;}
[](const std::vector<int> &in)-> decltype(auto) {return in;} // C++14
Now there are no copies, no temporaries, no dangling references, and no undefined behavior.
Who's at fault?
As to whether this is expected behavior, the answer is actually yes. The conditions for constructibility of a std::function are [func.wrap.func.con]:
f is Callable (20.9.12.2) for argument types ArgTypes... and return type R.
where, [func.wrap.func]:
A callable object f of type F is Callable for argument types ArgTypes and return type R if the expression
INVOKE (f, declval<ArgTypes>()..., R), considered as an unevaluated operand (Clause 5), is well
formed (20.9.2).
where, [func.require], emphasis mine:
Define INVOKE(f, t1, t2, ..., tN, R) as static_cast<void>(INVOKE (f, t1, t2, ..., tN)) if R is cv void, otherwise INVOKE(f, t1, t2, ..., tN) implicitly converted to R.
So, if we had:
T func();
std::function<T const&()> wrapped(func);
That actually meets all the standard requirements: INVOKE(func) is well-formed and while it returns T, T is implicitly convertible to T const&. So this isn't a gcc or clang bug. This is likely a standard defect, as I don't see why you would ever want to allow such a construction. This will never be valid, so the wording should likely require that if R is a reference type then F must return a reference type as well.
I did a bit of my own searching regarding the std::function constructor. It seems this part is an oversight in the interaction of std::function and the standard's Callable concept. std::function<R(Args...)>::function<F>(F) requires F to be Callable as R(Args...), which in itself seems reasonable. Callable for R(Args...) requires F's return type (when given arguments of types Args... to be implicitly convertible to R, which also in itself seems reasonable. Now when R is const R_ &, this will an allow implicit conversion of R_ to const R_ & because const references are allowed to bind to rvalues. This is not necessarily unsafe. E.g. consider a function f() that returns an int, but is considered callable as const int &().
const int &result = f();
if ( f == 5 )
{
// ...
}
There is no issue here because of C++'s rules for extending the lifetime of a temporary. However, the following has undefined behavior:
std::function<const int &()> fWrapped{f};
if ( fWrapped() == 5 )
{
// ...
}
This is because lifetime extension does not apply here. The temporary is created inside of std::function's operator() and is destroyed before the comparison.
Therefore, std::function's constructor probably should not rely on Callable alone, but enforce the additional restriction that implicit conversion of an rvalue to a const lvalue in order to bind to a reference is forbidden. Alternatively, Callable could be changed to never allow this conversion, at the expense of disallowing some safe usage (if only because of lifetime extension).
To make things more complicated yet, fWrapped() from the above example is perfectly safe to call, as long as you don't access the target of the dangling reference.
If you use:
return std::ref(in);
In your lambda it will work.
This will make your lambda's return type a std::reference_wrapper<std::vector<int>> which is implicitly convertible to std::vector<int>&.
The following code compiles without problem on gcc 4.8.1:
#include <utility>
struct foo
{
};
int main()
{
foo bar;
foo() = bar;
foo() = std::move( bar );
}
It seems the implicitly generated assignment operators for foo are not & ref-qualified and so can be invoked on rvalues. Is this correct according to the standard? If so, what reason is there for not requiring implicitly generated assignment operators to be & ref-qualified?
Why doesn't the standard require the following to be generated?
struct foo
{
foo & operator=( foo const & ) &;
foo & operator=( foo && ) &;
};
Well, there are certain legitimate use cases for assigning to an rvalue. To quote from Ref-qualifiers for assignment operators in the Standard Library:
There are only a few very specific types for which it makes sense to
support assigning to an rvalue. In particular, types that serve as a
proxy, e.g., vector<bool>::reference, and types whose assignment
operators are const-qualified (e.g., slice_array).
The C++ standard committee obviously felt that default assignment should not have an implicit ref qualifier - rather it should be explicitly declared. Indeed, there may be existing code which would stop working if all of a sudden all implicitly declared assignment operators didn't work with rvalues.
Granted, it's a bit hard to contrive an example where we want an implicitly declared assignment operator to work with rvalues, but the C++ standard committee likely doesn't want to take these kind of chances when it comes to preserving backwards compatibility. Code like this:
int foo_counter = 0;
struct Foo
{
Foo()
{
++foo_counter;
}
~Foo()
{
--foo_counter;
}
};
int main()
{
Foo() = Foo();
}
...wouldn't work anymore. And at the end of the day, the standards committee wants to make sure that previously valid C++ (no matter how stupid or contrived) continues to work in C++11.
It seems like your question is more "Why would assignment to an rvalue ever be useful?" rather than "Why doesn't the standard ref-qualify auto generated constructors?"
The reason assignment to an rvalue is allowed is because there are some cases where it is useful.
One example usage is with std::tie (link):
#include <set>
#include <tuple>
int main()
{
std::set<int> s;
std::set<int>::iterator iter;
bool inserted;
// unpacks the return value of insert into iter and inserted
std::tie(iter, inserted) = s.insert(7);
}
Example borrowed from cppreference.com then modified
boost::reference_wrapper<T> has an explicit T& constructor, while std::reference_wrapper<T> has an implicit one. So, in the following code:
foo = bar;
If foo is a boost::reference_wrapper, the code will fail to compile (which is good, since reference_wrapper does not have the same semantics of an actual reference.
If foo is a std::reference_wrapper, the code will "rebind" foo's reference to bar (instead of assigning the value as one might mistakenly expect it to).
This could result in elusive bugs... Consider the following example:
In version 1.0 of some hypothetical library:
void set_max(int& i, int a, int b) {
i = (a > b) ? a : b;
}
In a new version (1.1), set_max is converted to a template to accept integers of any width (or UDT's) without changing the interface:
template<typename T1, typename T2, typename T3>
void set_max(T1& i, T2 a, T3 b) {
i = (a > b) ? a : b;
}
Then finally, in some application using the library:
// i is a std::reference_wrapper<int> passed to this template function or class
set_max(i, 7, 11);
In this example, the library changes its implementation of set_max without changing the call interface. This would silently break any code that passes it a std::reference_wrapper as the argument would no longer convert to int& and would instead "rebind" to a dangling reference (a or b).
My question: Why did the standards committee elect to allow implicit conversion (from T& to std::reference_wrapper<T>) instead of following boost and making the T& constructor explicit?
Edit: (in response to the answer offered by Jonathan Wakely)...
The original demo (in the section above) is intentionally concise to show how a subtle library change could result in the use of std::reference_wrapper introducing bugs to an application.
The next demo is provided to show a real-world, legitimate use of reference_wrapper for "passing references through interfaces", in response to Jonathan Wakely's point.
From Developer/Vendor A
Something similar to std::bind but pretend it's specialized for some task:
template<typename FuncType, typename ArgType>
struct MyDeferredFunctionCall
{
MyDeferredFunctionCall(FuncType _f, ArgType _a) : f(_f), a(_a) {}
template<typename T>
void operator()(T t) { f(a, t); }
FuncType f;
ArgType a;
};
From Developer/Vendor B
A RunningMax functor class. Between version 1.0 and 1.1 of this imaginary library, the implementation of RunningMax was changed to be more generic, without changing its call interface. For purposes of this demo, the old implementation is defined in namespace lib_v1, while the new implementation in defined in lib_v2:
namespace lib_v1 {
struct RunningMax {
void operator()(int& curMax, int newVal) {
if ( newVal > curMax ) { curMax = newVal; }
}
};
}
namespace lib_v2 {
struct RunningMax {
template<typename T1, typename T2>
void operator()(T1& curMax, T2 newVal) {
if ( newVal > curMax ) { curMax = newVal; }
}
};
}
And last but not least, the end-user of all the above code:
Some developer using the code from Vendor/Developer A and B to accomplish some task:
int main() {
int _i = 7;
auto i = std::ref(_i);
auto f = lib_v2::RunningMax{};
using MyDFC = MyDeferredFunctionCall<decltype(f), decltype(i)>;
MyDFC dfc = MyDFC(f, i);
dfc(11);
std::cout << "i=[" << _i << "]" << std::endl; // should be 11
}
Note the following:
The end-user uses std::reference_wrapper the way in which it's intended.
Individually, none of the code has bugs or logical flaws, and everything worked perfectly with the original version of Vendor B's library.
boost::reference_wrapper would fail to compile upon upgrading the library, while std::reference_wrapper silently introduces a bug that may or may not be caught in regression tests.
Tracing such a bug would be difficult, since the "rebinding" is not a memory-error that tools such as valgrind would catch. Furthermore, the actual site of the misuse of std::reference_wrapper would be within Vendor B's library code, not the end-user's.
The bottom line: boost::reference_wrapper seems safer by declaring its T& constructor as explicit, and would prevent the introduction of a bug such as this. The decision to remove explicit constructor restriction in std::reference_wrapper seems like it compromised safety for convenience, something that should rarely occur in language/library design.
This would silently break any code that passes it a std::reference_wrapper as the argument would no longer convert to int& and would instead "rebind" to a dangling reference (a or b).
So don't do that.
reference_wrapper is for passing references through interfaces that would otherwise make a by-value copy, it's not for passing to arbitrary code.
Also:
// i is a std::reference_wrapper<int> (perhaps b/c std::decay wasn't used)
decay wouldn't change anything, it doesn't affect reference wrappers.
The reason implicit conversion (T& --> reference_wrapper<T>) is allowed for std::reference_wrapper<T>, but not boost::reference_wrapper<T>, is sufficiently explained in the DR-689 link provided by Nate Kohl. To summarize:
In 2007, the C++0x/C++11 Library Working Group (LWG) proposed change #DR-689 to section 20.8.3.1 [refwrap.const] of the standard:
The constructor of reference_wrapper is currently explicit.
The primary motivation behind this is the safety problem with respect
to rvalues, which is addressed by the proposed resolution of [DR-688].
Therefore we should consider relaxing the requirements
on the constructor since requests for the implicit conversion keep
resurfacing.
Proposed resolution: Remove explicit from the constructor of reference_wrapper.
It's worth pointing out:
boost::reference_wrapper has not been relaxed in such a way, nor does there appear to be a proposal for it, which creates an inconsistency between the semantics of boost::reference_wrapper and std::reference_wrapper.
Based on the verbiage in DR-689 (specifically the "requests keep surfacing" part) it seems likely that this change was simply viewed by the LWG as an acceptable tradeoff between safety and convenience (in contrast to its boost counterpart).
It's unclear whether the LWG anticipated other potential risks (such as those demonstrated in the examples provided on this page), since the only risk mentioned in DR-689 was that of binding to an rvalue (as described and resolved in the previous entry, DR-688).
In the following example, Foo is not doing what is intended, but I can't figure out why this is allowed to compile.
#include <string>
#include <iostream>
typedef std::string& T;
T Foo(int & i)
{
return T(i);
}
int main()
{
int a = 1;
std::string & s = Foo(a);
}
I discovered this with templates, but the typedef shows that its unrelated to templates. Needless to say, s is not a valid string here. I would think that constructing the value in the return of Foo would produce a compile error.
What am I missing here?
First of all, it worth nothing that the problem actually has no relationship to templates because this code compiles a well:
typedef std::string& T;
T Foo(int& i) {
return T(i);
}
The reason I think this compiles is that the return statement is equivalent to
return reinterpret_cast<T>(i);
in case T happens to be a reference members. ... and this, of course, compiles: You promised you knew what you were doing and asked the compiler kindly to believe you.
OK, found it at 5.2.3 [expr.type.conv] paragraph 1:
... If the expression list is a single expression, the type conversion expression is equivalent (in definedness, and if defined in meaning) to the corresponding cast expression (5.4). ...
... and 5.4 [expr.cast] paragraph 4:
The conversions performed by [other forms of casts] a reinterpret_cast (5.2.10) [...] can be performed using the cast notation of explicit type conversion. [...]
(the elisions cover cases involving user defined type, built-in type conversions, const conversions, etc.)
This has nothing to do with templates, you get the same result if T is just a typedef for std::string& rather than a deduced template parameter:
#include <string>
typedef std::string& T;
T Foo(int & i)
{
return T(i);
}
int main()
{
int a = 1;
std::string & s = Foo(a);
}
Dietmar's answer made me realise this can be further simplified to:
#include <string>
typedef std::string& T;
int main()
{
int a = 1;
std::string & s = T(a);
}
where T(a) is the same as the cast (T)a i.e. (std::string&)a which (according to the rules of 5.4 [expr.cast]) will do a const_cast if that's valid (which it isn't) or a static_cast if that's valid (which it isn't) or a static_cast followed by a const_cast if that's valid (which it isn't) or a reinterpret_cast if that's valid (which it is) or a reinterpret_cast followed by a const_cast if that's valid, otherwise the expression is ill-formed.
So as Dietmar said, it's the same as doing a reinterpret_cast, i.e.
std::string & s = reinterpret_cast<std::string&>(a);
I find it quite surprising that the original code compiles, but as it's the same as that line above, it's allowed to compile. Using the result of the cast is undefined behaviour though.
To avoid the surprise where T(a) is equivalent to a cast, use the new C++11 uniform initialization syntax, T{a}, which is always an initialization, not a cast expression.
Great question, investigating and answering it showed me a new gotcha I wasn't previously aware of, thanks to JaredC and Dietmar for the new piece of knowledge!