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

5.3 KiB
Raw Permalink Blame History

[forward]

22 General utilities library [utilities]

22.2 Utility components [utility]

22.2.4 Forward/move helpers [forward]

1

#

The library provides templated helper functions to simplify applying move semantics to an lvalue and to simplify the implementation of forwarding functions.

All functions specified in this subclause are signal-safe.

🔗

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

#

Mandates: For the second overload, is_lvalue_reference_v is false.

3

#

Returns: static_cast<T&&>(t).

4

#

[Example 1: template<class T, class A1, class A2> shared_ptr factory(A1&& a1, A2&& a2) {return shared_ptr(new T(std::forward(a1), std::forward(a2)));}struct A { A(int&, const double&);};

void g() { shared_ptr sp1 = factory(2, 1.414); // error: 2 will not bind to int&int i = 2; shared_ptr sp2 = factory(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.

In the second call to factory,A1 is deduced as int&, so i is forwarded to A's constructor as an lvalue.

In both cases, A2 is deduced as double, so 1.414 is forwarded to A's constructor as an rvalue.

— end example]

🔗

template<class T, class U> constexpr auto forward_like(U&& x) noexcept -> see below;

5

#

Mandates: T is a referenceable type ([defns.referenceable]).

6

#

  • (6.1)

    Let COPY_CONST(A, B) be const B if A is a const type, otherwise B.

  • (6.2)

    Let OVERRIDE_REF(A, B) be remove_reference_t&& if A is an rvalue reference type, otherwise B&.

  • (6.3)

    Let V beOVERRIDE_REF(T&&, COPY_CONST(remove_reference_t, remove_reference_t))

7

#

Returns: static_cast(x).

8

#

Remarks: The return type is V.

9

#

[Example 2: struct accessor { vector* 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]

🔗

template<class T> constexpr remove_reference_t<T>&& move(T&& t) noexcept;

10

#

Returns: static_cast<remove_reference_t&&>(t).

11

#

[Example 3: template<class T, class A1> shared_ptr factory(A1&& a1) {return shared_ptr(new T(std::forward(a1)));}struct A { A(); A(const A&); // copies from lvalues A(A&&); // moves from rvalues};

void g() { A a; shared_ptr sp1 = factory(a); // “a'' binds to A(const A&) shared_ptr sp2 = factory(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.

This binds to the constructor A(const A&), which copies the value from a.

In the second call to factory, because of the callstd::move(a),A1 is deduced as A, so a is forwarded as an rvalue.

This binds to the constructor A(A&&), which moves the value from a.

— end example]

🔗

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

#

Returns: std::move(x).