Namespaces
Variants

std:: forward_like

From cppreference.net
Utilities library
헤더 파일에 정의됨 <utility>
template < class T, class U >
constexpr auto && forward_like ( U && x ) noexcept ;
(C++23부터)

x 에 대한 참조를 반환하며, 이는 T&& 와 유사한 속성을 가집니다.

반환 타입은 아래와 같이 결정됩니다:

  1. 만약 std:: remove_reference_t < T > 가 const 한정 타입이라면, 반환 타입의 참조 타입은 const std:: remove_reference_t < U > 입니다. 그렇지 않다면 참조 타입은 std:: remove_reference_t < U > 입니다.
  2. 만약 T&& 가 lvalue 참조 타입이라면, 반환 타입 또한 lvalue 참조 타입입니다. 그렇지 않다면 반환 타입은 rvalue 참조 타입입니다.

만약 T referenceable type 가 아니라면, 프로그램은 형식에 맞지 않습니다.

목차

매개변수

x - T 타입처럼 전달되어야 하는 값

반환값

위에서 결정된 타입에 대한 x 의 참조입니다.

참고 사항

std::forward , std::move , std::as_const 와 마찬가지로, std::forward_like 는 표현식의 값 범주 에만 영향을 주거나 const 한정자를 추가하는 타입 캐스트입니다.

m 이 실제 멤버이고 따라서 o. m 가 유효한 표현식일 때, 이것은 일반적으로 C++20 코드에서 std:: forward < decltype ( o ) > ( o ) . m 로 표기됩니다.

이로 인해 세 가지 가능한 모델이 생기는데, 이를 merge , tuple , 그리고 language 라고 부릅니다.

  • merge : const 한정자를 병합하고 Owner 의 값 범주를 채택합니다.
  • tuple : std :: get < 0 > ( Owner ) 이 수행하는 작업으로, Owner std:: tuple < Member > 라고 가정합니다.
  • language : std:: forward < decltype ( Owner ) > ( o ) . m 이 수행하는 작업입니다.

std::forward_like 이 주로 대상으로 하는 시나리오는 "먼" 객체를 적응시키는 것입니다. tuple 시나리오나 language 시나리오 모두 이 주요 사용 사례에 적합하지 않기 때문에, std::forward_like 에는 merge 모델이 사용됩니다.

기능 테스트 매크로 표준 기능
__cpp_lib_forward_like 202207L (C++23) std::forward_like

가능한 구현

template<class T, class U>
constexpr auto&& forward_like(U&& x) noexcept
{
    constexpr bool is_adding_const = std::is_const_v<std::remove_reference_t<T>>;
    if constexpr (std::is_lvalue_reference_v<T&&>)
    {
        if constexpr (is_adding_const)
            return std::as_const(x);
        else
            return static_cast<U&>(x);
    }
    else
    {
        if constexpr (is_adding_const)
            return std::move(std::as_const(x));
        else
            return std::move(x);
    }
}

예제

#include <cstddef>
#include <iostream>
#include <memory>
#include <optional>
#include <type_traits>
#include <utility>
#include <vector>
struct TypeTeller
{
    void operator()(this auto&& self)
    {
        using SelfType = decltype(self);
        using UnrefSelfType = std::remove_reference_t<SelfType>;
        if constexpr (std::is_lvalue_reference_v<SelfType>)
        {
            if constexpr (std::is_const_v<UnrefSelfType>)
                std::cout << "const lvalue\n";
            else
                std::cout << "mutable lvalue\n";
        }
        else
        {
            if constexpr (std::is_const_v<UnrefSelfType>)
                std::cout << "const rvalue\n";
            else
                std::cout << "mutable rvalue\n";
        }
    }
};
struct FarStates
{
    std::unique_ptr<TypeTeller> ptr;
    std::optional<TypeTeller> opt;
    std::vector<TypeTeller> container;
    auto&& from_opt(this auto&& self)
    {
        return std::forward_like<decltype(self)>(self.opt.value());
        // std::forward<decltype(self)>(self).opt.value()를 사용하는 것은 허용됩니다,
        // std::optional이 적절한 접근자를 제공하기 때문입니다.
    }
    auto&& operator[](this auto&& self, std::size_t i)
    {
        return std::forward_like<decltype(self)>(self.container.at(i));
        // std::forward<decltype(self)>(self)[i]를 사용하는 것은 좋지 않습니다. 왜냐하면
        // 컨테이너들은 rvalue 서브스크립트 접근을 제공하지 않지만, 제공할 수는 있습니다.
    }
    auto&& from_ptr(this auto&& self)
    {
        if (!self.ptr)
            throw std::bad_optional_access{};
        return std::forward_like<decltype(self)>(*self.ptr);
        // *std::forward<decltype(self)>(self).ptr를 사용하는 것은 좋지 않습니다, 왜냐하면
        // std::unique_ptr<TypeTeller>는 항상 비-const 좌측값으로 역참조됩니다.
    }
};
int main()
{
    FarStates my_state
    {
        .ptr{std::make_unique<TypeTeller>()},
        .opt{std::in_place, TypeTeller{}},
        .container{std::vector<TypeTeller>(1)},
    };
    my_state.from_ptr()();
    my_state.from_opt()();
    my_state[0]();
    std::cout << '\n';
    std::as_const(my_state).from_ptr()();
    std::as_const(my_state).from_opt()();
    std::as_const(my_state)[0]();
    std::cout << '\n';
    std::move(my_state).from_ptr()();
    std::move(my_state).from_opt()();
    std::move(my_state)[0]();
    std::cout << '\n';
    std::move(std::as_const(my_state)).from_ptr()();
    std::move(std::as_const(my_state)).from_opt()();
    std::move(std::as_const(my_state))[0]();
    std::cout << '\n';
}

출력:

mutable lvalue
mutable lvalue
mutable lvalue
const lvalue
const lvalue
const lvalue
mutable rvalue
mutable rvalue
mutable rvalue
const rvalue
const rvalue
const rvalue

참고 항목

(C++11)
인수를 xvalue로 변환합니다
(함수 템플릿)
(C++11)
함수 인수를 전달하며 값 범주를 보존하기 위해 타입 템플릿 인수를 사용합니다
(함수 템플릿)
(C++17)
인수에 대한 const 참조를 얻습니다
(함수 템플릿)