Problems using std::unique_ptr with std::bind [duplicate] - c++

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));
};

Related

Why std::initializer_list cannot move? [duplicate]

Am I allowed to move elements out of a std::initializer_list<T>?
#include <initializer_list>
#include <utility>
template<typename T>
void foo(std::initializer_list<T> list)
{
for (auto it = list.begin(); it != list.end(); ++it)
{
bar(std::move(*it)); // kosher?
}
}
Since std::intializer_list<T> requires special compiler attention and does not have value semantics like normal containers of the C++ standard library, I'd rather be safe than sorry and ask.
No, that won't work as intended; you will still get copies. I'm pretty surprised by this, as I'd thought that initializer_list existed to keep an array of temporaries until they were move'd.
begin and end for initializer_list return const T *, so the result of move in your code is T const && — an immutable rvalue reference. Such an expression can't meaningfully be moved from. It will bind to an function parameter of type T const & because rvalues do bind to const lvalue references, and you will still see copy semantics.
Probably the reason for this is so the compiler can elect to make the initializer_list a statically-initialized constant, but it seems it would be cleaner to make its type initializer_list or const initializer_list at the compiler's discretion, so the user doesn't know whether to expect a const or mutable result from begin and end. But that's just my gut feeling, probably there's a good reason I'm wrong.
Update: I've written an ISO proposal for initializer_list support of move-only types. It's only a first draft, and it's not implemented anywhere yet, but you can see it for more analysis of the problem.
bar(std::move(*it)); // kosher?
Not in the way that you intend. You cannot move a const object. And std::initializer_list only provides const access to its elements. So the type of it is const T *.
Your attempt to call std::move(*it) will only result in an l-value. IE: a copy.
std::initializer_list references static memory. That's what the class is for. You cannot move from static memory, because movement implies changing it. You can only copy from it.
This won't work as stated, because list.begin() has type const T *, and there is no way you can move from a constant object. The language designers probably made that so in order to allow initializer lists to contain for instance string constants, from which it would be inappropriate to move.
However, if you are in a situation where you know that the initializer list contains rvalue expressions (or you want to force the user to write those) then there is a trick that will make it work (I was inspired by the answer by Sumant for this, but the solution is way simpler than that one). You need the elements stored in the initialiser list to be not T values, but values that encapsulate T&&. Then even if those values themselves are const qualified, they can still retrieve a modifiable rvalue.
template<typename T>
class rref_capture
{
T* ptr;
public:
rref_capture(T&& x) : ptr(&x) {}
operator T&& () const { return std::move(*ptr); } // restitute rvalue ref
};
Now instead of declaring an initializer_list<T> argument, you declare aninitializer_list<rref_capture<T> > argument. Here is a concrete example, involving a vector of std::unique_ptr<int> smart pointers, for which only move semantics is defined (so these objects themselves can never be stored in an initializer list); yet the initializer list below compiles without problem.
#include <memory>
#include <initializer_list>
class uptr_vec
{
typedef std::unique_ptr<int> uptr; // move only type
std::vector<uptr> data;
public:
uptr_vec(uptr_vec&& v) : data(std::move(v.data)) {}
uptr_vec(std::initializer_list<rref_capture<uptr> > l)
: data(l.begin(),l.end())
{}
uptr_vec& operator=(const uptr_vec&) = delete;
int operator[] (size_t index) const { return *data[index]; }
};
int main()
{
std::unique_ptr<int> a(new int(3)), b(new int(1)),c(new int(4));
uptr_vec v { std::move(a), std::move(b), std::move(c) };
std::cout << v[0] << "," << v[1] << "," << v[2] << std::endl;
}
One question does need an answer: if the elements of the initializer list should be true prvalues (in the example they are xvalues), does the language ensure that the lifetime of the corresponding temporaries extends to the point where they are used? Frankly, I don't think the relevant section 8.5 of the standard addresses this issue at all. However, reading 1.9:10, it would seem that the relevant full-expression in all cases encompasses the use of the initializer list, so I think there is no danger of dangling rvalue references.
I thought it might be instructive to offer a reasonable starting point for a workaround.
Comments inline.
#include <memory>
#include <vector>
#include <array>
#include <type_traits>
#include <algorithm>
#include <iterator>
template<class Array> struct maker;
// a maker which makes a std::vector
template<class T, class A>
struct maker<std::vector<T, A>>
{
using result_type = std::vector<T, A>;
template<class...Ts>
auto operator()(Ts&&...ts) const -> result_type
{
result_type result;
result.reserve(sizeof...(Ts));
using expand = int[];
void(expand {
0,
(result.push_back(std::forward<Ts>(ts)),0)...
});
return result;
}
};
// a maker which makes std::array
template<class T, std::size_t N>
struct maker<std::array<T, N>>
{
using result_type = std::array<T, N>;
template<class...Ts>
auto operator()(Ts&&...ts) const
{
return result_type { std::forward<Ts>(ts)... };
}
};
//
// delegation function which selects the correct maker
//
template<class Array, class...Ts>
auto make(Ts&&...ts)
{
auto m = maker<Array>();
return m(std::forward<Ts>(ts)...);
}
// vectors and arrays of non-copyable types
using vt = std::vector<std::unique_ptr<int>>;
using at = std::array<std::unique_ptr<int>,2>;
int main(){
// build an array, using make<> for consistency
auto a = make<at>(std::make_unique<int>(10), std::make_unique<int>(20));
// build a vector, using make<> because an initializer_list requires a copyable type
auto v = make<vt>(std::make_unique<int>(10), std::make_unique<int>(20));
}
Instead of using a std::initializer_list<T>, you can declare your argument as an array rvalue reference:
template <typename T>
void bar(T &&value);
template <typename T, size_t N>
void foo(T (&&list)[N] ) {
std::for_each(std::make_move_iterator(std::begin(list)),
std::make_move_iterator(std::end(list)),
&bar);
}
void baz() {
foo({std::make_unique<int>(0), std::make_unique<int>(1)});
}
See example using std::unique_ptr<int>: https://gcc.godbolt.org/z/2uNxv6
It seems not allowed in the current standard as already answered. Here is another workaround to achieve something similar, by defining the function as variadic instead of taking an initializer list.
#include <vector>
#include <utility>
// begin helper functions
template <typename T>
void add_to_vector(std::vector<T>* vec) {}
template <typename T, typename... Args>
void add_to_vector(std::vector<T>* vec, T&& car, Args&&... cdr) {
vec->push_back(std::forward<T>(car));
add_to_vector(vec, std::forward<Args>(cdr)...);
}
template <typename T, typename... Args>
std::vector<T> make_vector(Args&&... args) {
std::vector<T> result;
add_to_vector(&result, std::forward<Args>(args)...);
return result;
}
// end helper functions
struct S {
S(int) {}
S(S&&) {}
};
void bar(S&& s) {}
template <typename T, typename... Args>
void foo(Args&&... args) {
std::vector<T> args_vec = make_vector<T>(std::forward<Args>(args)...);
for (auto& arg : args_vec) {
bar(std::move(arg));
}
}
int main() {
foo<S>(S(1), S(2), S(3));
return 0;
}
Variadic templates can handle r-value references appropriately, unlike initializer_list.
In this example code, I used a set of small helper functions to convert the variadic arguments into a vector, to make it similar to the original code. But of course you can write a recursive function with variadic templates directly instead.
I have a much simpler implementation that makes use of a wrapper class which acts as a tag to mark the intention of moving the elements. This is a compile-time cost.
The wrapper class is designed to be used in the way std::move is used, just replace std::move with move_wrapper, but this requires C++17. For older specs, you can use an additional builder method.
You'll need to write builder methods/constructors that accept wrapper classes inside initializer_list and move the elements accordingly.
If you need some elements to be copied instead of being moved, construct a copy before passing it to initializer_list.
The code should be self-documented.
#include <iostream>
#include <vector>
#include <initializer_list>
using namespace std;
template <typename T>
struct move_wrapper {
T && t;
move_wrapper(T && t) : t(move(t)) { // since it's just a wrapper for rvalues
}
explicit move_wrapper(T & t) : t(move(t)) { // acts as std::move
}
};
struct Foo {
int x;
Foo(int x) : x(x) {
cout << "Foo(" << x << ")\n";
}
Foo(Foo const & other) : x(other.x) {
cout << "copy Foo(" << x << ")\n";
}
Foo(Foo && other) : x(other.x) {
cout << "move Foo(" << x << ")\n";
}
};
template <typename T>
struct Vec {
vector<T> v;
Vec(initializer_list<T> il) : v(il) {
}
Vec(initializer_list<move_wrapper<T>> il) {
v.reserve(il.size());
for (move_wrapper<T> const & w : il) {
v.emplace_back(move(w.t));
}
}
};
int main() {
Foo x{1}; // Foo(1)
Foo y{2}; // Foo(2)
Vec<Foo> v{Foo{3}, move_wrapper(x), Foo{y}}; // I want y to be copied
// Foo(3)
// copy Foo(2)
// move Foo(3)
// move Foo(1)
// move Foo(2)
}
This is one of cases where const_cast is good to use
Sum::Sum(std::initializer_list<Valuable>&& l)
{
for (auto& a : l)
{
auto&& arg = std::move(const_cast<Valuable&>(a));
Add(std::move(arg));
}
}
Consider the in<T> idiom described on cpptruths. The idea is to determine lvalue/rvalue at run-time and then call move or copy-construction. in<T> will detect rvalue/lvalue even though the standard interface provided by initializer_list is const reference.

Is std::initializer_list supposed to trigger a copy? [duplicate]

Am I allowed to move elements out of a std::initializer_list<T>?
#include <initializer_list>
#include <utility>
template<typename T>
void foo(std::initializer_list<T> list)
{
for (auto it = list.begin(); it != list.end(); ++it)
{
bar(std::move(*it)); // kosher?
}
}
Since std::intializer_list<T> requires special compiler attention and does not have value semantics like normal containers of the C++ standard library, I'd rather be safe than sorry and ask.
No, that won't work as intended; you will still get copies. I'm pretty surprised by this, as I'd thought that initializer_list existed to keep an array of temporaries until they were move'd.
begin and end for initializer_list return const T *, so the result of move in your code is T const && — an immutable rvalue reference. Such an expression can't meaningfully be moved from. It will bind to an function parameter of type T const & because rvalues do bind to const lvalue references, and you will still see copy semantics.
Probably the reason for this is so the compiler can elect to make the initializer_list a statically-initialized constant, but it seems it would be cleaner to make its type initializer_list or const initializer_list at the compiler's discretion, so the user doesn't know whether to expect a const or mutable result from begin and end. But that's just my gut feeling, probably there's a good reason I'm wrong.
Update: I've written an ISO proposal for initializer_list support of move-only types. It's only a first draft, and it's not implemented anywhere yet, but you can see it for more analysis of the problem.
bar(std::move(*it)); // kosher?
Not in the way that you intend. You cannot move a const object. And std::initializer_list only provides const access to its elements. So the type of it is const T *.
Your attempt to call std::move(*it) will only result in an l-value. IE: a copy.
std::initializer_list references static memory. That's what the class is for. You cannot move from static memory, because movement implies changing it. You can only copy from it.
This won't work as stated, because list.begin() has type const T *, and there is no way you can move from a constant object. The language designers probably made that so in order to allow initializer lists to contain for instance string constants, from which it would be inappropriate to move.
However, if you are in a situation where you know that the initializer list contains rvalue expressions (or you want to force the user to write those) then there is a trick that will make it work (I was inspired by the answer by Sumant for this, but the solution is way simpler than that one). You need the elements stored in the initialiser list to be not T values, but values that encapsulate T&&. Then even if those values themselves are const qualified, they can still retrieve a modifiable rvalue.
template<typename T>
class rref_capture
{
T* ptr;
public:
rref_capture(T&& x) : ptr(&x) {}
operator T&& () const { return std::move(*ptr); } // restitute rvalue ref
};
Now instead of declaring an initializer_list<T> argument, you declare aninitializer_list<rref_capture<T> > argument. Here is a concrete example, involving a vector of std::unique_ptr<int> smart pointers, for which only move semantics is defined (so these objects themselves can never be stored in an initializer list); yet the initializer list below compiles without problem.
#include <memory>
#include <initializer_list>
class uptr_vec
{
typedef std::unique_ptr<int> uptr; // move only type
std::vector<uptr> data;
public:
uptr_vec(uptr_vec&& v) : data(std::move(v.data)) {}
uptr_vec(std::initializer_list<rref_capture<uptr> > l)
: data(l.begin(),l.end())
{}
uptr_vec& operator=(const uptr_vec&) = delete;
int operator[] (size_t index) const { return *data[index]; }
};
int main()
{
std::unique_ptr<int> a(new int(3)), b(new int(1)),c(new int(4));
uptr_vec v { std::move(a), std::move(b), std::move(c) };
std::cout << v[0] << "," << v[1] << "," << v[2] << std::endl;
}
One question does need an answer: if the elements of the initializer list should be true prvalues (in the example they are xvalues), does the language ensure that the lifetime of the corresponding temporaries extends to the point where they are used? Frankly, I don't think the relevant section 8.5 of the standard addresses this issue at all. However, reading 1.9:10, it would seem that the relevant full-expression in all cases encompasses the use of the initializer list, so I think there is no danger of dangling rvalue references.
I thought it might be instructive to offer a reasonable starting point for a workaround.
Comments inline.
#include <memory>
#include <vector>
#include <array>
#include <type_traits>
#include <algorithm>
#include <iterator>
template<class Array> struct maker;
// a maker which makes a std::vector
template<class T, class A>
struct maker<std::vector<T, A>>
{
using result_type = std::vector<T, A>;
template<class...Ts>
auto operator()(Ts&&...ts) const -> result_type
{
result_type result;
result.reserve(sizeof...(Ts));
using expand = int[];
void(expand {
0,
(result.push_back(std::forward<Ts>(ts)),0)...
});
return result;
}
};
// a maker which makes std::array
template<class T, std::size_t N>
struct maker<std::array<T, N>>
{
using result_type = std::array<T, N>;
template<class...Ts>
auto operator()(Ts&&...ts) const
{
return result_type { std::forward<Ts>(ts)... };
}
};
//
// delegation function which selects the correct maker
//
template<class Array, class...Ts>
auto make(Ts&&...ts)
{
auto m = maker<Array>();
return m(std::forward<Ts>(ts)...);
}
// vectors and arrays of non-copyable types
using vt = std::vector<std::unique_ptr<int>>;
using at = std::array<std::unique_ptr<int>,2>;
int main(){
// build an array, using make<> for consistency
auto a = make<at>(std::make_unique<int>(10), std::make_unique<int>(20));
// build a vector, using make<> because an initializer_list requires a copyable type
auto v = make<vt>(std::make_unique<int>(10), std::make_unique<int>(20));
}
Instead of using a std::initializer_list<T>, you can declare your argument as an array rvalue reference:
template <typename T>
void bar(T &&value);
template <typename T, size_t N>
void foo(T (&&list)[N] ) {
std::for_each(std::make_move_iterator(std::begin(list)),
std::make_move_iterator(std::end(list)),
&bar);
}
void baz() {
foo({std::make_unique<int>(0), std::make_unique<int>(1)});
}
See example using std::unique_ptr<int>: https://gcc.godbolt.org/z/2uNxv6
It seems not allowed in the current standard as already answered. Here is another workaround to achieve something similar, by defining the function as variadic instead of taking an initializer list.
#include <vector>
#include <utility>
// begin helper functions
template <typename T>
void add_to_vector(std::vector<T>* vec) {}
template <typename T, typename... Args>
void add_to_vector(std::vector<T>* vec, T&& car, Args&&... cdr) {
vec->push_back(std::forward<T>(car));
add_to_vector(vec, std::forward<Args>(cdr)...);
}
template <typename T, typename... Args>
std::vector<T> make_vector(Args&&... args) {
std::vector<T> result;
add_to_vector(&result, std::forward<Args>(args)...);
return result;
}
// end helper functions
struct S {
S(int) {}
S(S&&) {}
};
void bar(S&& s) {}
template <typename T, typename... Args>
void foo(Args&&... args) {
std::vector<T> args_vec = make_vector<T>(std::forward<Args>(args)...);
for (auto& arg : args_vec) {
bar(std::move(arg));
}
}
int main() {
foo<S>(S(1), S(2), S(3));
return 0;
}
Variadic templates can handle r-value references appropriately, unlike initializer_list.
In this example code, I used a set of small helper functions to convert the variadic arguments into a vector, to make it similar to the original code. But of course you can write a recursive function with variadic templates directly instead.
I have a much simpler implementation that makes use of a wrapper class which acts as a tag to mark the intention of moving the elements. This is a compile-time cost.
The wrapper class is designed to be used in the way std::move is used, just replace std::move with move_wrapper, but this requires C++17. For older specs, you can use an additional builder method.
You'll need to write builder methods/constructors that accept wrapper classes inside initializer_list and move the elements accordingly.
If you need some elements to be copied instead of being moved, construct a copy before passing it to initializer_list.
The code should be self-documented.
#include <iostream>
#include <vector>
#include <initializer_list>
using namespace std;
template <typename T>
struct move_wrapper {
T && t;
move_wrapper(T && t) : t(move(t)) { // since it's just a wrapper for rvalues
}
explicit move_wrapper(T & t) : t(move(t)) { // acts as std::move
}
};
struct Foo {
int x;
Foo(int x) : x(x) {
cout << "Foo(" << x << ")\n";
}
Foo(Foo const & other) : x(other.x) {
cout << "copy Foo(" << x << ")\n";
}
Foo(Foo && other) : x(other.x) {
cout << "move Foo(" << x << ")\n";
}
};
template <typename T>
struct Vec {
vector<T> v;
Vec(initializer_list<T> il) : v(il) {
}
Vec(initializer_list<move_wrapper<T>> il) {
v.reserve(il.size());
for (move_wrapper<T> const & w : il) {
v.emplace_back(move(w.t));
}
}
};
int main() {
Foo x{1}; // Foo(1)
Foo y{2}; // Foo(2)
Vec<Foo> v{Foo{3}, move_wrapper(x), Foo{y}}; // I want y to be copied
// Foo(3)
// copy Foo(2)
// move Foo(3)
// move Foo(1)
// move Foo(2)
}
This is one of cases where const_cast is good to use
Sum::Sum(std::initializer_list<Valuable>&& l)
{
for (auto& a : l)
{
auto&& arg = std::move(const_cast<Valuable&>(a));
Add(std::move(arg));
}
}
Consider the in<T> idiom described on cpptruths. The idea is to determine lvalue/rvalue at run-time and then call move or copy-construction. in<T> will detect rvalue/lvalue even though the standard interface provided by initializer_list is const reference.

std::initializer_list alternatives for noncopyable types

I know that trying to use a std::initializer_list<NonCopyable> leads to an error because the elements are copied into the temporary array represented by the initializer_list. I have also read some explanation on why it would not be alright to have rvalue references in the list, which I'm fine with.
The problem is that I would like to pass noncopyable things not in order to move from them, but only const-access them, so the argument about rvalues does not apply. What can I do to retain, if possible, the list initialization syntax and the reference semantics (no wrappers, no raw pointers)?
NonCopyable a{...}, b{...};
ListInitialized c{a, b};
I think I'm missing something extremely obvious here.
Update:
This works(*),
ListInitialized(std::initializer_list<std::reference_wrapper<NonCopyable>>) {...}
but won't accept rvalues. It would be nice if I could simply pass a list of anything that could go into const NonCopyable&.
(*) I know I wrote "no wrappers" but this affects neither the calling code nor the iteration over the list.
You can give ListInitialized a variadic constructor template:
struct ListInitialized
{
template <class... T>
ListInitialized(const T... &arg);
};
If you need to make sure it can only be instantiated with the correct type, consider suitable SFINAE:
struct ListInitialized
{
template <
class... T,
class Sfinae = std::enable_if_t<std::is_same<std::decay_t<T>, NonCopyable> &&...
>
ListInitialized(const T... &arg);
};
In addition to the comments and answers above, I found that this minimalistic wrapper fulfills my needs:
#include <initializer_list>
#include <utility>
struct S {
S() { }
S(const S&) = delete; // Non-copyable
void f() const { }
};
template<class T>
class const_reference_wrapper {
public:
const_reference_wrapper(const T& ref_) : ref(ref_) { }
operator const T&() const { return ref; }
private:
const T& ref;
};
struct T {
T(std::initializer_list<const_reference_wrapper<S>> l) : c(l.size()) {
for(const S& i : l) // note: const auto& can't be used here, but it would be the same for std::reference_wrapper
i.f(); // we can do something with the elements
}
int c;
};
int main() {
S a, b;
T t{a, b, S{}}; // we can mix lvalues and rvalues with a natural syntax
return t.c; // correctly returns 3
}
Of course, care needs to be taken to ensure that any rvalue passed through this will live through the time it is being referenced.

Why does the creation of an initializer_list causes copies? [duplicate]

Am I allowed to move elements out of a std::initializer_list<T>?
#include <initializer_list>
#include <utility>
template<typename T>
void foo(std::initializer_list<T> list)
{
for (auto it = list.begin(); it != list.end(); ++it)
{
bar(std::move(*it)); // kosher?
}
}
Since std::intializer_list<T> requires special compiler attention and does not have value semantics like normal containers of the C++ standard library, I'd rather be safe than sorry and ask.
No, that won't work as intended; you will still get copies. I'm pretty surprised by this, as I'd thought that initializer_list existed to keep an array of temporaries until they were move'd.
begin and end for initializer_list return const T *, so the result of move in your code is T const && — an immutable rvalue reference. Such an expression can't meaningfully be moved from. It will bind to an function parameter of type T const & because rvalues do bind to const lvalue references, and you will still see copy semantics.
Probably the reason for this is so the compiler can elect to make the initializer_list a statically-initialized constant, but it seems it would be cleaner to make its type initializer_list or const initializer_list at the compiler's discretion, so the user doesn't know whether to expect a const or mutable result from begin and end. But that's just my gut feeling, probably there's a good reason I'm wrong.
Update: I've written an ISO proposal for initializer_list support of move-only types. It's only a first draft, and it's not implemented anywhere yet, but you can see it for more analysis of the problem.
bar(std::move(*it)); // kosher?
Not in the way that you intend. You cannot move a const object. And std::initializer_list only provides const access to its elements. So the type of it is const T *.
Your attempt to call std::move(*it) will only result in an l-value. IE: a copy.
std::initializer_list references static memory. That's what the class is for. You cannot move from static memory, because movement implies changing it. You can only copy from it.
This won't work as stated, because list.begin() has type const T *, and there is no way you can move from a constant object. The language designers probably made that so in order to allow initializer lists to contain for instance string constants, from which it would be inappropriate to move.
However, if you are in a situation where you know that the initializer list contains rvalue expressions (or you want to force the user to write those) then there is a trick that will make it work (I was inspired by the answer by Sumant for this, but the solution is way simpler than that one). You need the elements stored in the initialiser list to be not T values, but values that encapsulate T&&. Then even if those values themselves are const qualified, they can still retrieve a modifiable rvalue.
template<typename T>
class rref_capture
{
T* ptr;
public:
rref_capture(T&& x) : ptr(&x) {}
operator T&& () const { return std::move(*ptr); } // restitute rvalue ref
};
Now instead of declaring an initializer_list<T> argument, you declare aninitializer_list<rref_capture<T> > argument. Here is a concrete example, involving a vector of std::unique_ptr<int> smart pointers, for which only move semantics is defined (so these objects themselves can never be stored in an initializer list); yet the initializer list below compiles without problem.
#include <memory>
#include <initializer_list>
class uptr_vec
{
typedef std::unique_ptr<int> uptr; // move only type
std::vector<uptr> data;
public:
uptr_vec(uptr_vec&& v) : data(std::move(v.data)) {}
uptr_vec(std::initializer_list<rref_capture<uptr> > l)
: data(l.begin(),l.end())
{}
uptr_vec& operator=(const uptr_vec&) = delete;
int operator[] (size_t index) const { return *data[index]; }
};
int main()
{
std::unique_ptr<int> a(new int(3)), b(new int(1)),c(new int(4));
uptr_vec v { std::move(a), std::move(b), std::move(c) };
std::cout << v[0] << "," << v[1] << "," << v[2] << std::endl;
}
One question does need an answer: if the elements of the initializer list should be true prvalues (in the example they are xvalues), does the language ensure that the lifetime of the corresponding temporaries extends to the point where they are used? Frankly, I don't think the relevant section 8.5 of the standard addresses this issue at all. However, reading 1.9:10, it would seem that the relevant full-expression in all cases encompasses the use of the initializer list, so I think there is no danger of dangling rvalue references.
I thought it might be instructive to offer a reasonable starting point for a workaround.
Comments inline.
#include <memory>
#include <vector>
#include <array>
#include <type_traits>
#include <algorithm>
#include <iterator>
template<class Array> struct maker;
// a maker which makes a std::vector
template<class T, class A>
struct maker<std::vector<T, A>>
{
using result_type = std::vector<T, A>;
template<class...Ts>
auto operator()(Ts&&...ts) const -> result_type
{
result_type result;
result.reserve(sizeof...(Ts));
using expand = int[];
void(expand {
0,
(result.push_back(std::forward<Ts>(ts)),0)...
});
return result;
}
};
// a maker which makes std::array
template<class T, std::size_t N>
struct maker<std::array<T, N>>
{
using result_type = std::array<T, N>;
template<class...Ts>
auto operator()(Ts&&...ts) const
{
return result_type { std::forward<Ts>(ts)... };
}
};
//
// delegation function which selects the correct maker
//
template<class Array, class...Ts>
auto make(Ts&&...ts)
{
auto m = maker<Array>();
return m(std::forward<Ts>(ts)...);
}
// vectors and arrays of non-copyable types
using vt = std::vector<std::unique_ptr<int>>;
using at = std::array<std::unique_ptr<int>,2>;
int main(){
// build an array, using make<> for consistency
auto a = make<at>(std::make_unique<int>(10), std::make_unique<int>(20));
// build a vector, using make<> because an initializer_list requires a copyable type
auto v = make<vt>(std::make_unique<int>(10), std::make_unique<int>(20));
}
Instead of using a std::initializer_list<T>, you can declare your argument as an array rvalue reference:
template <typename T>
void bar(T &&value);
template <typename T, size_t N>
void foo(T (&&list)[N] ) {
std::for_each(std::make_move_iterator(std::begin(list)),
std::make_move_iterator(std::end(list)),
&bar);
}
void baz() {
foo({std::make_unique<int>(0), std::make_unique<int>(1)});
}
See example using std::unique_ptr<int>: https://gcc.godbolt.org/z/2uNxv6
It seems not allowed in the current standard as already answered. Here is another workaround to achieve something similar, by defining the function as variadic instead of taking an initializer list.
#include <vector>
#include <utility>
// begin helper functions
template <typename T>
void add_to_vector(std::vector<T>* vec) {}
template <typename T, typename... Args>
void add_to_vector(std::vector<T>* vec, T&& car, Args&&... cdr) {
vec->push_back(std::forward<T>(car));
add_to_vector(vec, std::forward<Args>(cdr)...);
}
template <typename T, typename... Args>
std::vector<T> make_vector(Args&&... args) {
std::vector<T> result;
add_to_vector(&result, std::forward<Args>(args)...);
return result;
}
// end helper functions
struct S {
S(int) {}
S(S&&) {}
};
void bar(S&& s) {}
template <typename T, typename... Args>
void foo(Args&&... args) {
std::vector<T> args_vec = make_vector<T>(std::forward<Args>(args)...);
for (auto& arg : args_vec) {
bar(std::move(arg));
}
}
int main() {
foo<S>(S(1), S(2), S(3));
return 0;
}
Variadic templates can handle r-value references appropriately, unlike initializer_list.
In this example code, I used a set of small helper functions to convert the variadic arguments into a vector, to make it similar to the original code. But of course you can write a recursive function with variadic templates directly instead.
I have a much simpler implementation that makes use of a wrapper class which acts as a tag to mark the intention of moving the elements. This is a compile-time cost.
The wrapper class is designed to be used in the way std::move is used, just replace std::move with move_wrapper, but this requires C++17. For older specs, you can use an additional builder method.
You'll need to write builder methods/constructors that accept wrapper classes inside initializer_list and move the elements accordingly.
If you need some elements to be copied instead of being moved, construct a copy before passing it to initializer_list.
The code should be self-documented.
#include <iostream>
#include <vector>
#include <initializer_list>
using namespace std;
template <typename T>
struct move_wrapper {
T && t;
move_wrapper(T && t) : t(move(t)) { // since it's just a wrapper for rvalues
}
explicit move_wrapper(T & t) : t(move(t)) { // acts as std::move
}
};
struct Foo {
int x;
Foo(int x) : x(x) {
cout << "Foo(" << x << ")\n";
}
Foo(Foo const & other) : x(other.x) {
cout << "copy Foo(" << x << ")\n";
}
Foo(Foo && other) : x(other.x) {
cout << "move Foo(" << x << ")\n";
}
};
template <typename T>
struct Vec {
vector<T> v;
Vec(initializer_list<T> il) : v(il) {
}
Vec(initializer_list<move_wrapper<T>> il) {
v.reserve(il.size());
for (move_wrapper<T> const & w : il) {
v.emplace_back(move(w.t));
}
}
};
int main() {
Foo x{1}; // Foo(1)
Foo y{2}; // Foo(2)
Vec<Foo> v{Foo{3}, move_wrapper(x), Foo{y}}; // I want y to be copied
// Foo(3)
// copy Foo(2)
// move Foo(3)
// move Foo(1)
// move Foo(2)
}
This is one of cases where const_cast is good to use
Sum::Sum(std::initializer_list<Valuable>&& l)
{
for (auto& a : l)
{
auto&& arg = std::move(const_cast<Valuable&>(a));
Add(std::move(arg));
}
}
Consider the in<T> idiom described on cpptruths. The idea is to determine lvalue/rvalue at run-time and then call move or copy-construction. in<T> will detect rvalue/lvalue even though the standard interface provided by initializer_list is const reference.

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));
};