utility_forward

utility_forward (std::forward)

이 페이지는 C++ 표준 라이브러리의 std::forward 함수 템플릿에 대해 설명해요. std::forward는 전달 참조(forwarding reference)로 받은 인자를 원래의 값 범주(value category) 그대로 다른 함수에 전달하는 데 사용해요. 이를 통해 완벽 전달(perfect forwarding)을 구현할 수 있어요.

출처: cppreference

본문

개요

<utility> 헤더에 정의되어 있어요.

정의 오버로드 버전
template < class T > T && forward ( typename std :: remove_reference < T >:: type & t ) noexcept ; (1) (since C++11) (until C++14)
template < class T > constexpr T && forward ( std :: remove_reference_t < T >& t ) noexcept ; (since C++14)
template < class T > T && forward ( typename std :: remove_reference < T >:: type && t ) noexcept ; (2) (since C++11) (until C++14)
template < class T > constexpr T && forward ( std :: remove_reference_t < T >&& t ) noexcept ; (since C++14)

t가 전달 참조(즉, cv 한정이 없는 함수 템플릿 매개변수에 대한 rvalue 참조로 선언된 함수 인자)일 때, 이 오버로드는 그 인자를 호출 함수에 전달되었을 때의 값 범주 그대로 다른 함수에 전달해요.

예를 들어 다음과 같은 래퍼에서 사용된다면, 템플릿은 아래에 설명된 대로 동작해요.

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이 전달되면, Tstd::string으로 추론되고(std::string&, const std::string&, std::string&&이 아님), std::forward는 rvalue 참조가 foo에 전달되도록 보장해요.
  • wrapper() 호출에 const lvalue std::string이 전달되면, Tconst std::string&으로 추론되고, std::forward는 const lvalue 참조가 foo에 전달되도록 보장해요.
  • wrapper() 호출에 비-const lvalue std::string이 전달되면, Tstd::string&으로 추론되고, std::forward는 비-const lvalue 참조가 foo에 전달되도록 보장해요.

이 오버로드는 표현식(예: 함수 호출)의 결과가 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로 전달하려는 시도, 예를 들어 lvalue 참조 타입 T로 오버로드 (2)를 인스턴스화하는 것은 컴파일 타임 오류예요.

참고 사항

전달 참조(T&&가 함수 매개변수로 사용될 때) 뒤에 숨은 특별한 추론 규칙은 템플릿 인자 추론을, 그 외 세부 사항은 전달 참조를 참고해요.

매개변수

이름 설명
t 전달할 객체

반환값

static_cast < T &&> ( t )

복잡도

상수 시간(constant).

예제

이 예제는 클래스 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) 인자를 xvalue로 변환해요 (함수 템플릿)
move_if_noexcept (C++11) 이동 생성자가 던지지 않으면 인자를 xvalue로 변환해요 (함수 템플릿)

더 알아보기 (Learn more)

cppreference