std::assignable_from

std::assignable_from (대입 가능성 개념)

RHS가 지정한 타입과 값 범주(value category)의 표준 라이브러리 개념(concept)이에요. RHS 형태의 표현식을 LHS로 지정된 타입의 lvalue 표현식에 대입할 수 있는지를 명세해요. C++20부터 있어요.

출처: cppreference

본문

<concepts> 헤더에 정의돼 있어요.

template< class LHS, class RHS >
concept assignable_from =
    std::is_lvalue_reference_v<LHS> &&
    std::common_reference_with<
        const std::remove_reference_t<LHS>&,
        const std::remove_reference_t<RHS>&> &&
    requires(LHS lhs, RHS&& rhs) {
        { lhs = std::forward<RHS>(rhs) } -> std::same_as<LHS>;
    };

개념 assignable_from<LHS, RHS>는 RHS가 지정한 타입과 값 범주의 표현식이 LHS로 지정된 타입의 lvalue 표현식에 대입될 수 있음을 명세해요.

의미 요구사항

다음이 주어졌을 때:

  • lhs: decltype((lhs))LHS인 객체 lcopy를 가리키는 lvalue.
  • rhs: decltype((rhs))RHS인 표현식.
  • rcopy: rhs와 같은 별개의 객체.

assignable_from<LHS, RHS>는 다음일 때만 모델링돼요.

  • std::addressof(lhs = rhs) == std::addressof(lcopy) (즉 대입 표현식이 왼쪽 피연산자를 가리키는 lvalue를 산출).
  • lhs = rhs를 평가한 뒤:
    • lhsrcopy와 같음. 단 rhslcopy를 가리키는 비-const xvalue(즉 자기 대입-이동)인 경우는 제외.
    • rhs가 glvalue이면:
      • 비-const xvalue이면, 그것이 가리키는 객체는 유효하지만 불특정 상태에 있음.
      • 그렇지 않으면 그것이 가리키는 객체는 수정되지 않음.

동등성 보존(Equality preservation)

표준 라이브러리 개념의 requires 표현식에서 선언된 표현식들은 (달리 명시되지 않는 한) 동등성 보존(equality-preserving)이어야 해요.

참고

대입이 전함수(total function)일 필요는 없어요. 특히 어떤 객체 x에 대입하면 다른 객체 y가 수정될 수 있다면, x = y=의 정의역에 속하지 않을 가능성이 커요. 이는 보통 오른쪽 피연산자가 왼쪽 피연산자에 (직접적이든 간접적이든) 소유될 때 일어나요(예: 노드 기반 자료구조에서 노드를 가리키는 스마트 포인터, 또는 std::vector<std::any> 같은 것).

예제를 보면요.

#include <atomic>
#include <concepts>
#include <string>

int main()
{
    // 일반적인 기본 사용, lvalue 참조 대입을 확인
    static_assert(std::is_assignable_v<int&, int>);
    static_assert(std::assignable_from<int&, int>);

    // 기본 타입은 rvalue에 대한 대입을 지원하지 않아요
    static_assert(!std::is_assignable_v<int, int>);
    static_assert(!std::assignable_from<int, int>);

    // std::assignable_from은 모든 유효한 대입 표현식을 받아들이진 않아요:

    // rvalue 참조 대입
    static_assert(std::is_assignable_v<std::string&&, std::string>);
    static_assert(!std::assignable_from<std::string&&, std::string>);

    // rvalue 대입
    static_assert(std::is_assignable_v<std::string, std::string>);
    static_assert(!std::assignable_from<std::string, std::string>);

    // std::atomic::operator= 는 값을 반환
    static_assert(std::is_assignable_v<std::atomic<int>&, int>);
    static_assert(!std::assignable_from<std::atomic<int>&, int>);
}

이렇게 assignable_fromis_assignable보다 더 엄격해서, 대입 결과가 LHS 타입 그 자체로 돌아와야 해요.

참고 문헌

  • C++23 표준 (ISO/IEC 14882:2024): 18.4.8 Concept assignable_from [concept.assignable]
  • C++20 표준 (ISO/IEC 14882:2020): 18.4.8 Concept assignable_from [concept.assignable]

더 알아보기 (Learn more)

cppreference