Files
cppdraft_translate/cppdraft/forward.md
2025-10-25 03:02:53 +03:00

153 lines
5.3 KiB
Markdown
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

[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.5Signal 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.45referenceable 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)