Spec-Zone.ru › C++

std::forward

Определено в заголовке <utility>
(1)
template< class T >
T&& forward( typename std::remove_reference<T>::type& t ) noexcept;
(с C++11)
(до C++14)
template< class T >
constexpr T&& forward( std::remove_reference_t<T>& t ) noexcept;
(с C++14)
(2)
template< class T >
T&& forward( typename std::remove_reference<T>::type&& t ) noexcept;
(с C++11)
(до C++14)
template< class T >
constexpr T&& forward( std::remove_reference_t<T>&& t ) noexcept;
(с C++14)
1) Передает lvalues как lvalues или как rvalues, в зависимости от T.

Когда t является ссылкой для перенаправления (аргумент функции, который объявлен как ссылка на rvalue для cv-неквалифицированного параметра шаблона функции), этот перегруз передает аргумент другой функции с категорией значений, которую он имел при передаче в вызывающую функцию.

Например, если используется в оболочке, такой как следующая, шаблон ведет себя, как описано ниже:

template<class T>
void wrapper(T&& arg)
{
    // arg is always lvalue
    foo(std::forward<T>(arg)); // Forward as lvalue or as rvalue, depending on T
}
  • Если вызов wrapper() передает rvalue std::string, тогда T выводится как std::string (а не std::string&, const std::string&, или std::string&&), и std::forward гарантирует, что в foo передается ссылка на rvalue.
  • Если вызов wrapper() передает const lvalue std::string, тогда T выводится как const std::string&, и std::forward гарантирует, что в foo передается ссылка на const lvalue.
  • Если вызов wrapper() передает non-const lvalue std::string, тогда T выводится как std::string&, и std::forward гарантирует, что в foo передается ссылка на non-const lvalue.
2) Передает rvalues как rvalues и запрещает передачу rvalues как lvalues.

Этот перегруз позволяет передать результат выражения (например, вызов функции), который может быть rvalue или lvalue, как исходную категорию значений аргумента ссылки для перенаправления.

Например, если оболочка не просто передает свой аргумент, но вызывает член-функцию для аргумента и передает ее результат:

// transforming wrapper
template<class T>
void wrapper(T&& arg)
{
    foo(forward<decltype(forward<T>(arg).get())>(forward<T>(arg).get()));
}

где тип arg может быть

struct Arg
{
    int i = 1;
    int  get() && { return i; } // call to this overload is rvalue
    int& get() &  { return i; } // call to this overload is lvalue
};

Попытка передать rvalue как lvalue, например, путем инстанцирования формы (2) с типом ссылки lvalue T, является ошибкой времени компиляции.

Примечания

См. вывод аргументов шаблона для особых правил, связанных со ссылками для перенаправления (T&& в качестве параметра функции) и ссылками для перенаправления для других деталей.

Параметры

t - передаваемый объект

Возвращаемое значение

static_cast<T&&>(t)

Сложность

Постоянная.

Пример

Этот пример демонстрирует идеальную передачу параметра(ов) в аргумент конструктора класса T. Также показана идеальная передача параметра пакета.

#include <iostream>
#include <memory>
#include <utility>
 
struct A
{
    A(int&& n) { std::cout << "rvalue overload, n=" << n << '\n'; }
    A(int& n)  { std::cout << "lvalue overload, n=" << n << '\n'; }
};
 
class B
{
public:
    template<class T1, class T2, class T3>
    B(T1&& t1, T2&& t2, T3&& t3) :
        a1_{std::forward<T1>(t1)},
        a2_{std::forward<T2>(t2)},
        a3_{std::forward<T3>(t3)}
    {}
 
private:
    A a1_, a2_, a3_;
};
 
template<class T, class U>
std::unique_ptr<T> make_unique1(U&& u)
{
    return std::unique_ptr<T>(new T(std::forward<U>(u)));
}
 
template<class T, class... U>
std::unique_ptr<T> make_unique2(U&&... u)
{
    return std::unique_ptr<T>(new T(std::forward<U>(u)...));
}
 
auto make_B(auto&&... args) // since C++20
{
    return B(std::forward<decltype(args)>(args)...);
}
 
int main()
{
    auto p1 = make_unique1<A>(2); // rvalue
    int i = 1;
    auto p2 = make_unique1<A>(i); // lvalue
 
    std::cout << "B\n";
    auto t = make_unique2<B>(2, i, 3);
 
    std::cout << "make_B\n";
    [[maybe_unused]] B b = make_B(4, i, 5);
}

Вывод:

rvalue overload, n=2
lvalue overload, n=1
B
rvalue overload, n=2
lvalue overload, n=1
rvalue overload, n=3
make_B
rvalue overload, n=4
lvalue overload, n=1
rvalue overload, n=5

См. также

move
(C++11)
получает ссылку на rvalue
(шаблон функции)
move_if_noexcept
(C++11)
получает ссылку на rvalue, если конструктор перемещения не выбрасывает исключение
(шаблон функции)

© cppreference.com
Licensed under the Creative Commons Attribution-ShareAlike Unported License v3.0.
https://en.cppreference.com/w/cpp/utility/forward

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API