153 lines
5.3 KiB
Markdown
153 lines
5.3 KiB
Markdown
[forward]
|
||
|
||
# 22 General utilities library [[utilities]](./#utilities)
|
||
|
||
## 22.2 Utility components [[utility]](utility#forward)
|
||
|
||
### 22.2.4 Forward/move helpers [forward]
|
||
|
||
[1](#1)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/utilities.tex#L328)
|
||
|
||
The library provides templated helper functions to simplify
|
||
applying move semantics to an lvalue and to simplify the implementation
|
||
of forwarding functions[.](#1.sentence-1)
|
||
|
||
All functions specified in this subclause are [signal-safe](support.signal#def:evaluation,signal-safe "17.14.5 Signal handlers [support.signal]")[.](#1.sentence-2)
|
||
|
||
[ð](#lib:forward)
|
||
|
||
`template<class T> constexpr T&& forward(remove_reference_t<T>& t) noexcept;
|
||
template<class T> constexpr T&& forward(remove_reference_t<T>&& t) noexcept;
|
||
`
|
||
|
||
[2](#2)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/utilities.tex#L345)
|
||
|
||
*Mandates*: For the second overload, is_lvalue_reference_v<T> is false[.](#2.sentence-1)
|
||
|
||
[3](#3)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/utilities.tex#L349)
|
||
|
||
*Returns*: static_cast<T&&>(t)[.](#3.sentence-1)
|
||
|
||
[4](#4)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/utilities.tex#L353)
|
||
|
||
[*Example [1](#example-1)*: template<class T, class A1, class A2> shared_ptr<T> factory(A1&& a1, A2&& a2) {return shared_ptr<T>(new T(std::forward<A1>(a1), std::forward<A2>(a2)));}struct A { A(int&, const double&);};
|
||
|
||
void g() { shared_ptr<A> sp1 = factory<A>(2, 1.414); // error: 2 will not bind to int&int i = 2;
|
||
shared_ptr<A> sp2 = factory<A>(i, 1.414); // OK}
|
||
|
||
In the first call to factory,A1 is deduced as int, so 2 is forwarded
|
||
to A's constructor as an rvalue[.](#4.sentence-1)
|
||
|
||
In the second call to factory,A1 is deduced as int&, so i is forwarded
|
||
to A's constructor as an lvalue[.](#4.sentence-2)
|
||
|
||
In
|
||
both cases, A2 is deduced as double, so
|
||
1.414 is forwarded to A's constructor as an rvalue[.](#4.sentence-3)
|
||
|
||
â *end example*]
|
||
|
||
[ð](#lib:forward_like)
|
||
|
||
`template<class T, class U>
|
||
constexpr auto forward_like(U&& x) noexcept -> see below;
|
||
`
|
||
|
||
[5](#5)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/utilities.tex#L389)
|
||
|
||
*Mandates*: T is a referenceable type ([[defns.referenceable]](defns.referenceable "3.45 referenceable type"))[.](#5.sentence-1)
|
||
|
||
[6](#6)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/utilities.tex#L393)
|
||
|
||
- [(6.1)](#6.1)
|
||
|
||
Let *COPY_CONST*(A, B) be const B if A is a const type, otherwise B[.](#6.1.sentence-1)
|
||
|
||
- [(6.2)](#6.2)
|
||
|
||
Let *OVERRIDE_REF*(A, B) be remove_reference_t<B>&& if A is an rvalue reference type, otherwise B&[.](#6.2.sentence-1)
|
||
|
||
- [(6.3)](#6.3)
|
||
|
||
Let V be*OVERRIDE_REF*(T&&, *COPY_CONST*(remove_reference_t<T>, remove_reference_t<U>))
|
||
|
||
[7](#7)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/utilities.tex#L408)
|
||
|
||
*Returns*: static_cast<V>(x)[.](#7.sentence-1)
|
||
|
||
[8](#8)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/utilities.tex#L412)
|
||
|
||
*Remarks*: The return type is V[.](#8.sentence-1)
|
||
|
||
[9](#9)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/utilities.tex#L416)
|
||
|
||
[*Example [2](#example-2)*: struct accessor { vector<string>* container; decltype(auto) operator[](this auto&& self, size_t i) {return std::forward_like<decltype(self)>((*container)[i]); }};void g() { vector v{"a"s, "b"s};
|
||
accessor a{&v};
|
||
string& x = a[0]; // OK, binds to lvalue reference string&& y = std::move(a)[0]; // OK, is rvalue reference string const&& z = std::move(as_const(a))[1]; // OK, is const&& string& w = as_const(a)[1]; // error: will not bind to non-const} â *end example*]
|
||
|
||
[ð](#lib:move,function)
|
||
|
||
`template<class T> constexpr remove_reference_t<T>&& move(T&& t) noexcept;
|
||
`
|
||
|
||
[10](#10)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/utilities.tex#L444)
|
||
|
||
*Returns*: static_cast<remove_reference_t<T>&&>(t)[.](#10.sentence-1)
|
||
|
||
[11](#11)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/utilities.tex#L448)
|
||
|
||
[*Example [3](#example-3)*: template<class T, class A1> shared_ptr<T> factory(A1&& a1) {return shared_ptr<T>(new T(std::forward<A1>(a1)));}struct A { A();
|
||
A(const A&); // copies from lvalues A(A&&); // moves from rvalues};
|
||
|
||
void g() { A a;
|
||
shared_ptr<A> sp1 = factory<A>(a); // âa'' binds to A(const A&) shared_ptr<A> sp2 = factory<A>(std::move(a)); // âa'' binds to A(A&&)}
|
||
|
||
In the first call to factory,A1 is deduced as A&, so a is forwarded
|
||
as a non-const lvalue[.](#11.sentence-1)
|
||
|
||
This binds to the constructor A(const A&),
|
||
which copies the value from a[.](#11.sentence-2)
|
||
|
||
In the second call to factory, because of the callstd::move(a),A1 is deduced as A, so a is forwarded
|
||
as an rvalue[.](#11.sentence-3)
|
||
|
||
This binds to the constructor A(A&&),
|
||
which moves the value from a[.](#11.sentence-4)
|
||
|
||
â *end example*]
|
||
|
||
[ð](#lib:move_if_noexcept)
|
||
|
||
`template<class T> constexpr conditional_t<
|
||
!is_nothrow_move_constructible_v<T> && is_copy_constructible_v<T>, const T&, T&&>
|
||
move_if_noexcept(T& x) noexcept;
|
||
`
|
||
|
||
[12](#12)
|
||
|
||
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/utilities.tex#L488)
|
||
|
||
*Returns*: std::move(x)[.](#12.sentence-1)
|