Normally, rvalues can bind to const references (const SomeType&
). It's built into the language. However, std::reference_wrapper<const T>
does not accept an rvalue as its constructor argument since the corresponding overload is deliberately deleted. What is the reason for this inconsistency? std::reference_wrapper
is "advertised" as the alternative to a reference variable for cases when we must pass by value but would like to preserve reference semantics.
In other words, if the rvalue to const &
binding is considered safe, since it's built into the language, why did the designers of C++11 not allow rvalues to be wrapped in std::reference_wrapper<const T>
?
When would this come handy, you may ask. For example:
class MyType{};
class Foo {
public:
Foo(const MyType& param){}
};
class MultiFoo {
public:
MultiFoo(std::initializer_list<std::reference_wrapper<const MyType>> params){}
};
int main()
{
Foo foo{MyType{}}; //ok
MultiFoo multiFoo{MyType{}, MyType{}}; //error
}
INTRODUCTION
Normally
T const&
andT&&
can extend the lifetime of a temporary directly bound to it, but this is not applicable if the reference is "hiding" behind a constructor.Since
std::reference_wrapper
is copyable (by intention), the handle to the referenced object can outlive the temporary if thestd::reference_wrapper
is used in such a way that the handle escapes the scope where the temporary is created.This will lead to a lifetime mismatch between the handle and the referred to object (ie. the temporary).
LET'S PLAY "MAKE BELIEVE"
Imagine having the below, illegal, snippet; where we pretend that
std::reference_wrapper
has a constructor that would accept a temporary.Let's also pretend that the temporary passed to the constructor will have its lifetime extended (even though this isn't the case, in real life it will be "dead" right after
(1)
).Since a temporary is created with automatic storage duration, it will be allocated on the storage bound to the scope inside
get_ref
.When
get_ref
later returns, our temporary will be destroyed. This means that ourval
inmain
would refer to an invalid object, since the original object is no longer in existance.The above is the reason why
std::reference_wrapper
's constructor doesn't have an overload that accepts temporaries.ANOTHER EXAMPLE
The lifetime of
std::string { "temporary" }
will not be extended, as can be read in the standard.Note: it's important to note that a constructor is nothing more than a "fancy" function, called upon object construction.