std::reference_wrapper, constructor implementation explaination - c++

I have been trying to understand the implementation of std::reference_wrapper, from here, which is as follows:
namespace detail {
template <class T> constexpr T& FUN(T& t) noexcept { return t; }
template <class T> void FUN(T&&) = delete;
}
template <class T>
class reference_wrapper {
public:
// types
typedef T type;
// construct/copy/destroy
template <class U, class = decltype(
detail::FUN<T>(std::declval<U>()),
std::enable_if_t<!std::is_same_v<reference_wrapper, std::remove_cvref_t<U>>>()
)>
constexpr reference_wrapper(U&& u) noexcept(noexcept(detail::FUN<T>(std::forward<U>(u))))
: _ptr(std::addressof(detail::FUN<T>(std::forward<U>(u)))) {}
reference_wrapper(const reference_wrapper&) noexcept = default;
// assignment
reference_wrapper& operator=(const reference_wrapper& x) noexcept = default;
// access
constexpr operator T& () const noexcept { return *_ptr; }
constexpr T& get() const noexcept { return *_ptr; }
template< class... ArgTypes >
constexpr std::invoke_result_t<T&, ArgTypes...>
operator() ( ArgTypes&&... args ) const {
return std::invoke(get(), std::forward<ArgTypes>(args)...);
}
private:
T* _ptr;
};
Although the implementation of std::reference_wrapper has been discussed hereand here,but none of it discusses the constructor implementation which i am confused about. My confusions are :
1.) Constructor is a template function , taking a type param (U) different from the template class param T. I have seen member functions of a class being template functions and depending on different type params then the type param of the template class, but i can't think how it is works here. There is a related question here, but i am not able to relate it with my confusion.
2.)I see the second type parameter in the constructor is further used to sfinae out something, but i did not understand howdetail::FUN<T>(std::declval<U>()) is evaluated.
Can someone please explain ?
Edit: This is an example added from microsoft.docs. A snippet of the
example is:
int i = 1;
std::reference_wrapper<int> rwi(i); // A.1
rwi.get() = -1;
std::cout << "i = " << i << std::endl; //Prints -1
With the implementation of reference_wrapper , and from A.1, how is the constructor of the reference_wrapper called ? Assuming that detail::FUN<T>(std::declval<U>() will be called with detail::FUN<T>(std::declval<int>(), should be a substitution failure because of the deleted overload(Assuming std::declval<int> will be read as an rvalue reference to int). What am i missing here ?

It's a technique you can use when you want the behaviour of the "forwarding reference", U&& in this case, but at the same time restrict what can bind to it.
Deduction of T is aided by the deduction guide provided below. The detail::FUN<T>(std::declval<U>()) is there to ensure that the constructor is disabled when U is deduced to be an rvalue reference, by selecting the deleted overload and producing an invalid expression. It is also disabled if the U is another reference wrapper, in which case the copy constructor should be selected.
Here are a few examples of valid and invalid reference_wrappers:
int i = 1;
// OK: FUN<int>(std::declval<int&>()) is valid
std::reference_wrapper<int> rwi(i);
// error: forming pointer to reference
std::reference_wrapper<int&> rwi2(i);
// OK, uses deduction guide to find T = int
std::reference_wrapper rwi3(i);
std::reference_wrapper rwi4(++i);
// error: cannot deduce T, since there is no deduction guide for
// rvalue reference to T
std::reference_wrapper rwi5(std::move(i));
// error: substitution failure of FUN<int>(int&&)
std::reference_wrapper<int> rwi6(std::move(i));
std::reference_wrapper<int> rwi7(i++);
std::reference_wrapper<int> rwi8(i + i);
std::reference_wrapper<int> rwi9(2);
As you can see, the call to the deleted FUN<T>(T&&) only comes into play in the last 4 cases: when you explicitly specify T, but attempt to construct from an rvalue.

Related

Allow implicit type conversion during template evaluation

I'm writing a wrapper class for C++ types, which allows me to instrument when a wrapped object is constructed, accessed, modified, and destroyed. To make this transparent for the original code, I include implicit conversion functions back to the underlying type, but this fails when a wrapped object is passed directly to a template since implicit conversions aren't evaluated. Here's some code that demonstrates this problem:
#include <utility>
// simplified wrapper class
template <typename T>
class wrap {
T t;
public:
wrap() : t() {}
wrap(const T& _t) : t(_t) {}
wrap(T&& _t) : t(std::move(_t)) {}
constexpr operator T&() { return t; }
constexpr operator const T&() const { return t; }
};
// an example templated function
template <typename T>
bool is_same(const T& t1, const T& t2) { return t1 == t2;}
// second invocation fails due to template substitution failure
bool problem() {
wrap<int> w(5);
return is_same(static_cast<int>(w), 5) && is_same<>(w, 5);
}
I can resolve this manually by performing a static_cast on the wrapped variable at each template call site (as shown in the first invocation), but this doesn't scale well since I'm working with a large code base. Similar questions suggest inlining each template function as a friend function, but this also requires identifying and copying each template, which doesn't scale.
I'd appreciate any advice on how to (1) workaround this conversion problem with templated functions, or (2) otherwise instrument a variable at source-level without this problem.
The fault in this example lies with is_same. It declares that it requires two arguments of the same type, which is a requirement it does not need, and fails to require that type to have an ==, which it does need.
Granted, it is common to find C++ that poorly constrains template functions because it is difficult and verbose to do otherwise. Authors take a practical shortcut. That said, isn't the approach to fix the interface of is_same?
// C++17 version. Close to std::equal_to<>::operator().
template <typename T, typename U>
constexpr auto is_same(T&& t, U&& u)
noexcept(noexcept(std::forward<T>(t) == std::forward<U>(u)))
-> decltype(std::forward<T>(t) == std::forward<U>(u))
{
return std::forward<T>(t) == std::forward<U>(u);
}
With a corrected is_same, the code just works.
There are other examples one can imagine which may require two arguments to have the same type. For example, if the return type depends on the argument type and the return value can come from either:
template <typename T>
T& choose(bool choose_left, T& left, T& right) {
return choose_left ? left : right;
}
This is much rarer. But it might actually require thought to decide whether to use the underlying or wrapper type. If you have this enhanced behavior in the wrapper type, and conditionally use a wrapped value or an underlying value, should the underlying value be wrapped to continue to get the enhanced behavior, or do we drop the enhancement? Even if you could make this silently choose one of those two behaviors, would you want to?
However, you can still make it easier to get the value than to say static_cast<T>(...), for example by providing an accessor:
// given wrap<int> w and int i
is_same(w.value(), 5);
choose_left(true, w.value(), i);
I have a few other important comments:
wrap() : t() {}
This requires T be default constructible. = default does the right thing.
wrap(const T& _t) : t(_t) {}
wrap(T&& _t) : t(std::move(_t)) {}
These are not explicit. A T is implicitly convertible to a wrap<T> and vice versa. This does not work well in C++. For example, true ? w : i is not well-formed. This causes std::equality_comparable_with<int, wrap<int>> to be false, which would be a reasonable requirement for is_same. Wrapper types should probably be explicitly constructed, and can be implicitly converted to the underlying type.
constexpr operator T&() { return t; }
constexpr operator const T&() const { return t; }
These are not ref-qualified, so they return lvalue references even if the wrapper is an rvalue. That seems ill-advised.
Finally, construction and conversion only take into account the exact type T. But any place T is used, it might be implicitly converted from some other type. And two conversions are disallowed in C++. So for a wrapper type, one has a decision to make, and that often means allowing construction from anything a T is constructible from.
With a pointer wrapper function it can work, if you treat the "inner" guy as a pointer.
This is not a complete solution, but should be a good starting point for you (for instance, you need to carefully write the copy and move ctors).
You can play with this code in here.
Disclaimer: I took the idea from Andrei Alexandrescu from this presentation.
#include <iostream>
using namespace std;
template <typename T>
class WrapperPtr
{
T * ptr;
public:
WrapperPtr(const WrapperPtr&){
// ???
}
WrapperPtr(WrapperPtr&&) {
// ???
}
WrapperPtr(const T & other)
: ptr(new T(other)) {}
WrapperPtr(T * other)
: ptr(other) {}
~WrapperPtr()
{
// ????
delete ptr;
}
T * operator -> () { return ptr; }
T & operator * () { return *ptr; }
const T & operator * () const { return *ptr; }
bool operator == (T other) const { other == *ptr; }
operator T () { return *ptr; }
};
// an example templated function
template <typename T>
bool my_is_same(const T& t1, const T& t2) { return t1 == t2;}
bool problem() {
WrapperPtr<int> w(5);
return my_is_same(static_cast<int>(w), 5) && my_is_same(*w, 5);
}

std::forward and copy constructor

I have started leaning C++ recently. And I have a question on std::forward with lvalue reference and rvalue reference.
In my understanding, The Func(mc) in the following code suppose to call
Func(T& t) because of template parameter deduction rule. And copy constructor of MyClass should be called inside the function with a message, "copy constructor". However I cannot get it when I run the program.
I checked that std::forwad with rvalue reference and copy constructor is working well in other lines.
Please help me to understand what happen in the code. If I make easy mistake or misunderstanding, I am sorry for taking your time. Thank you very much.
class MyClass {
public:
MyClass() { printf("constructor.\n"); };
MyClass(MyClass&) { printf("copy constructor.\n"); };
MyClass(const MyClass&) { printf("const copy constructor.\n"); };
MyClass(MyClass&&) { printf("move constructor.\n"); };
int val = 3;
};
template <typename T>
void Func(T&& t) {
T new_t_(std::forward<T>(t));
new_t_.val *= 2;
};
main() {
MyClass mc;
Func(mc); // lvalue <- Func(T&)
Func(MyClass()); // rsvalue <- Func(T&&)
printf("mc.val=%d\n", mc.val); // this is for check
MyClass mc2(mc); // this is for check of copy constructor
}
Output when I run program is following,
constructor.
constructor.
move constructor.
mc.val=6
copy constructor.
I think it should have "copy constructor" between the first and the second "constructor" messages.
Thank you very much again.
Func(mc);
This call will deduce T to be MyClass&. Note the reference. This is due to the way perfect forwarding has been introduced into C++: A forwarding reference such as the T&& function parameter of Func will be deduced to be an lvalue reference if the corresponding function argument is an lvalue-expression; otherwise (for xvalues and prvalues) it will not be deduced to be a reference type.
The type deduced for T will then be reference-collapsed with the && from the function parameter T&& t to form the final function parameter type. In the case Func(mc), T == MyClass&, so the function parameter becomes MyClass& &&, collapsed to MyClass&.
Since T == MyClass&, the declaration of the local variable new_t_ will declare a reference in this case. No new object will be created:
template <>
void Func<MyClass&>(MyClass& t) {
MyClass& new_t_(std::forward<MyClass&>(t));
new_t_.val *= 2;
}
Func(MyClass());
Here, the function argument is the prvalue-expression MyClass(). T will be deduced to MyClass (without reference). The function template instantiation produced looks like this:
template <>
void Func<MyClass>(MyClass&& t) {
MyClass new_t_(std::forward<MyClass>(t));
new_t_.val *= 2;
}
If you want to copy/move the function argument into a local variable, the std::decay metafunction can be used - or, more specific to the OP's problem, the std::remove_reference metafunction. E.g.
template <typename T>
void Func(T&& t) {
using DT = typename std::decay<T>::type;
DT new_t_(std::forward<T>(t));
new_t_.val *= 2;
}

Problems using std::unique_ptr with std::bind [duplicate]

I wonder how the following can be done
void f(string &&s) {
std::string i(move(s));
/* other stuff */
}
int main() {
std::string s;
bind(f, s)(); // Error.
bind(f, move(s))(); // Error.
bind(f, ref(s))(); // Error.
}
How can I pass an rvalue reference and store it as an rvalue reference (possibly wrapped) in the call wrapper? I know I can manually write up a class like std::reference_wrapper<> that has a conversion function to T&&, but I would rather want to avoid that and use Standard technology.
I implemented it like AProgrammer recommends:
template<typename T> struct adv {
T t;
explicit adv(T &&t):t(forward<T>(t)) {}
template<typename ...U> T &&operator()(U &&...) {
return forward<T>(t);
}
};
template<typename T> adv<T> make_adv(T &&t) {
return adv<T>{forward<T>(t)};
}
namespace std {
template<typename T>
struct is_bind_expression< adv<T> > : std::true_type {};
}
Now I can say
void f(string &&s) {
std::string i(move(s));
/* other stuff */
}
int main() {
std::string s;
bind(f, make_adv(move(s)))(); // Works!
}
If we pass an lvalue to make_adv, it will forward it as an lvalue referring to the input argument, so it can be used as a replacement for std::ref, in this case.
My take on this.
20.8.10.1.2/10 in N3225
The values of the bound arguments v1, v2, ..., vN and their corresponding types V1, V2, ..., VN
depend on the types TiD derived from the call to bind and the cv-qualifiers cv of the call wrapper g as
follows:
if TiD is reference_wrapper, the argument is tid.get() and its type Vi is T&;
if the value of is_bind_expression::value is true, the argument is tid(std::forward(uj)...)
and its type Vi is result_of::type;
if the value j of is_placeholder::value is not zero, the argument is std::forward(uj)
and its type Vi is Uj&&;
otherwise, the value is tid and its type Vi is TiD cv &.
So the only possibility to have a rvalue reference is to have is_bind_expression<TiD>::value true or is_placeholder<TiD>::value not zero. The second possibility has implications you don't want and achieving the wanted result with the first would imply that the problem we are trying to solve is solved if we restrict to the standard provided types. So, the only possibility would be to provide your own wrapper and a specialisation for is_bind_expression<TiD> (that is allowed by 20.8.10.1.1/1) as I don't see one.
How can I pass an rvalue reference and store it as an rvalue reference in the call wrapper?
The problem here is that such a bind function object can be invoked multiple times. If the function object forwarded a bound parameter as rvalue this would obviously only work once. So, this is a bit of a safety issue.
But in some cases this kind of forwarding is exactly what you want. You could use a lambda as an intermediary:
bind([](string& s){f(move(s));},move(s));
Basically, I came up with this bind+lambda combination as a workaround for a missing "move-capture".
I was googling for "reference_wrapper for rvalues" when I stumbled on this question.
Not sure whether my answer would be useful, it is not related to std::bind and actually doesn't work with it, but for some other use cases it might help somebody.
Here's my attempt to implement rvalue_reference_wrapper:
#pragma once
#include <type_traits>
#include <memory>
#include <utility>
template<class T>
class rvalue_reference_wrapper
{
public:
static_assert(::std::is_object<T>::value, "rvalue_reference_wrapper<T> requires T to be an object type.");
using type = T;
rvalue_reference_wrapper(T& ref_value) = delete;
rvalue_reference_wrapper(T&& ref_value) noexcept
: _pointer(::std::addressof(ref_value))
{
}
operator T&&() && noexcept
{
return ::std::move(*_pointer);
}
T&& get() && noexcept
{
return ::std::move(*_pointer);
}
template<class... ArgTypes>
auto operator()(ArgTypes&&... args) &&
-> decltype(::std::invoke(::std::declval<rvalue_reference_wrapper<T>>().get(), ::std::forward<ArgTypes>(args)...))
{
return (::std::invoke(::std::move(*this).get(), ::std::forward<ArgTypes>(args)...));
}
private:
T* _pointer;
};
template<class T>
inline rvalue_reference_wrapper<T> rv_ref(T& ref_value) = delete;
template<class T>
inline ::std::enable_if_t<!(::std::is_lvalue_reference<T>::value), rvalue_reference_wrapper<T>> rv_ref(T&& ref_value) noexcept
{
return rvalue_reference_wrapper<T>(::std::forward<T>(ref_value));
}
#ifdef _MSC_VER
namespace std
{
template<class T>
struct _Unrefwrap_helper<rvalue_reference_wrapper<T>>
{
using type = T &&;
static constexpr bool _Is_refwrap = true;
};
}
#else
#pragma error("TODO : implement...")
#endif
The last specialization in namespace std allows MSVC's implementation of standard library to work with my type, e.g. when using std::make_tuple:
int a = 42;
auto p_int = std::make_unique<int>(42);
auto test_tuple = std::make_tuple(42, std::ref(a), rv_ref(std::move(p_int)));
static_assert(std::is_same<decltype(test_tuple), std::tuple<int, int &, std::unique_ptr<int>&&>>::value, "unexpected result");
I believe it would not be hard to implement similar "unwrapping" logic for other standard library implementations.
You can use a mutable lambda object.
auto func = [=]() mutable {
f(std::move(s));
};

Implement a forward function using universal reference

The implementation of std::forward in VS2013 is
template<class _Ty> inline
_Ty&& forward(typename remove_reference<_Ty>::type& _Arg)
{ // forward an lvalue
return (static_cast<_Ty&&>(_Arg));
}
template<class _Ty> inline
_Ty&& forward(typename remove_reference<_Ty>::type&& _Arg) _NOEXCEPT
{ // forward anything
static_assert(!is_lvalue_reference<_Ty>::value, "bad forward call");
return (static_cast<_Ty&&>(_Arg));
}
One version for lvalue reference, one version for rvalue reference. Why not just use a universal reference for both rvalue and lvalue reference:
template <typename T, typename U>
T&& Forward(U&& arg) {
return static_cast<T&&>(arg);
}
Your version is not standard-compliant, as std::forward is is required to not compile when called with on an rvalue if T is an l-value reference. From [forward]:
template <class T> T&& forward(typename remove_reference<T>::type& t) noexcept;
template <class T> T&& forward(typename remove_reference<T>::type&& t) noexcept;
2 Returns: static_cast<T&&>(t).
3 if the second form is instantiated with an lvalue reference type, the program is ill-formed.
std::forward is defined in this way to ensure that (some) misuses of std::forward do not compile. See n2951 for more discussion (although even n2951 does not use this exact form).
I'm expanding a bit on the problem you've pointed out here.
Your version would introduce a reference-dangling case if you attempt to bind a newly created rvalue to a l-value reference.
As Mankarse linked, the n2951 paper cites this case and, by simplifying it a bit, you can summarize it with the following code
#include <iostream>
using namespace std;
template <typename T, typename U>
T&& Forward(U&& arg) {
return static_cast<T&&>(arg);
}
class Container
{
int data_;
public:
explicit Container(int data = 1) // Set the data variable
: data_(data) {}
~Container() {data_ = -1;} // When destructed, first set the data to -1
void test()
{
if (data_ <= 0)
std::cout << "OPS! A is destructed!\n";
else
std::cout << "A = " << data_ << '\n';
}
};
// This class has a reference to the data object
class Reference_To_Container_Wrapper
{
const Container& a_;
public:
explicit Reference_To_Container_Wrapper(const Container& a) : a_(a) {}
// (I) This line causes problems! This "Container" returned will be destroyed and cause troubles!
const Container get() const {return a_;} // Build a new Container out of the reference and return it
};
template <class T>
struct ReferenceContainer
{
T should_be_valid_lvalue_ref;
template <class U> // U = Reference_To_Container_Wrapper
ReferenceContainer(U&& u) :
// We store a l-value reference to a container, but the container is from line (I)
// and thus will soon get destroyed and we'll have a dangling reference
should_be_valid_lvalue_ref(Forward<T>(std::move(u).get())) {}
};
int main() {
Container a(42); // This lives happily with perfect valid data
ReferenceContainer<const Container&> rc( (Reference_To_Container_Wrapper(a)) ); // Parenthesis necessary otherwise most vexing parse will think this is a function pointer..
// rc now has a dangling reference
Container newContainer = rc.should_be_valid_lvalue_ref; // From reference to Container
newContainer.test();
return 0;
}
which outputs "OPS! A is destructed!"
if you just add a "&" in the line
const Container& get() const {return a_;}
the above works just fine.
http://ideone.com/SyUXss

Is there a reference_wrapper<> for rvalue references?

I wonder how the following can be done
void f(string &&s) {
std::string i(move(s));
/* other stuff */
}
int main() {
std::string s;
bind(f, s)(); // Error.
bind(f, move(s))(); // Error.
bind(f, ref(s))(); // Error.
}
How can I pass an rvalue reference and store it as an rvalue reference (possibly wrapped) in the call wrapper? I know I can manually write up a class like std::reference_wrapper<> that has a conversion function to T&&, but I would rather want to avoid that and use Standard technology.
I implemented it like AProgrammer recommends:
template<typename T> struct adv {
T t;
explicit adv(T &&t):t(forward<T>(t)) {}
template<typename ...U> T &&operator()(U &&...) {
return forward<T>(t);
}
};
template<typename T> adv<T> make_adv(T &&t) {
return adv<T>{forward<T>(t)};
}
namespace std {
template<typename T>
struct is_bind_expression< adv<T> > : std::true_type {};
}
Now I can say
void f(string &&s) {
std::string i(move(s));
/* other stuff */
}
int main() {
std::string s;
bind(f, make_adv(move(s)))(); // Works!
}
If we pass an lvalue to make_adv, it will forward it as an lvalue referring to the input argument, so it can be used as a replacement for std::ref, in this case.
My take on this.
20.8.10.1.2/10 in N3225
The values of the bound arguments v1, v2, ..., vN and their corresponding types V1, V2, ..., VN
depend on the types TiD derived from the call to bind and the cv-qualifiers cv of the call wrapper g as
follows:
if TiD is reference_wrapper, the argument is tid.get() and its type Vi is T&;
if the value of is_bind_expression::value is true, the argument is tid(std::forward(uj)...)
and its type Vi is result_of::type;
if the value j of is_placeholder::value is not zero, the argument is std::forward(uj)
and its type Vi is Uj&&;
otherwise, the value is tid and its type Vi is TiD cv &.
So the only possibility to have a rvalue reference is to have is_bind_expression<TiD>::value true or is_placeholder<TiD>::value not zero. The second possibility has implications you don't want and achieving the wanted result with the first would imply that the problem we are trying to solve is solved if we restrict to the standard provided types. So, the only possibility would be to provide your own wrapper and a specialisation for is_bind_expression<TiD> (that is allowed by 20.8.10.1.1/1) as I don't see one.
How can I pass an rvalue reference and store it as an rvalue reference in the call wrapper?
The problem here is that such a bind function object can be invoked multiple times. If the function object forwarded a bound parameter as rvalue this would obviously only work once. So, this is a bit of a safety issue.
But in some cases this kind of forwarding is exactly what you want. You could use a lambda as an intermediary:
bind([](string& s){f(move(s));},move(s));
Basically, I came up with this bind+lambda combination as a workaround for a missing "move-capture".
I was googling for "reference_wrapper for rvalues" when I stumbled on this question.
Not sure whether my answer would be useful, it is not related to std::bind and actually doesn't work with it, but for some other use cases it might help somebody.
Here's my attempt to implement rvalue_reference_wrapper:
#pragma once
#include <type_traits>
#include <memory>
#include <utility>
template<class T>
class rvalue_reference_wrapper
{
public:
static_assert(::std::is_object<T>::value, "rvalue_reference_wrapper<T> requires T to be an object type.");
using type = T;
rvalue_reference_wrapper(T& ref_value) = delete;
rvalue_reference_wrapper(T&& ref_value) noexcept
: _pointer(::std::addressof(ref_value))
{
}
operator T&&() && noexcept
{
return ::std::move(*_pointer);
}
T&& get() && noexcept
{
return ::std::move(*_pointer);
}
template<class... ArgTypes>
auto operator()(ArgTypes&&... args) &&
-> decltype(::std::invoke(::std::declval<rvalue_reference_wrapper<T>>().get(), ::std::forward<ArgTypes>(args)...))
{
return (::std::invoke(::std::move(*this).get(), ::std::forward<ArgTypes>(args)...));
}
private:
T* _pointer;
};
template<class T>
inline rvalue_reference_wrapper<T> rv_ref(T& ref_value) = delete;
template<class T>
inline ::std::enable_if_t<!(::std::is_lvalue_reference<T>::value), rvalue_reference_wrapper<T>> rv_ref(T&& ref_value) noexcept
{
return rvalue_reference_wrapper<T>(::std::forward<T>(ref_value));
}
#ifdef _MSC_VER
namespace std
{
template<class T>
struct _Unrefwrap_helper<rvalue_reference_wrapper<T>>
{
using type = T &&;
static constexpr bool _Is_refwrap = true;
};
}
#else
#pragma error("TODO : implement...")
#endif
The last specialization in namespace std allows MSVC's implementation of standard library to work with my type, e.g. when using std::make_tuple:
int a = 42;
auto p_int = std::make_unique<int>(42);
auto test_tuple = std::make_tuple(42, std::ref(a), rv_ref(std::move(p_int)));
static_assert(std::is_same<decltype(test_tuple), std::tuple<int, int &, std::unique_ptr<int>&&>>::value, "unexpected result");
I believe it would not be hard to implement similar "unwrapping" logic for other standard library implementations.
You can use a mutable lambda object.
auto func = [=]() mutable {
f(std::move(s));
};