std:: assignable_from

From cppreference.com
Defined in header <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 > ;

} ;
(since C++20)

The concept assignable_from<LHS, RHS> specifies that an expression of the type and value category specified by RHS can be assigned to an lvalue expression whose type is specified by LHS .

Semantic requirements

Given

  • lhs , an lvalue that refers to an object lcopy such that decltype ( ( lhs ) ) is LHS ,
  • rhs , an expression such that decltype ( ( rhs ) ) is RHS ,
  • rcopy , a distinct object that is equal to rhs ,

assignable_from<LHS, RHS> is modeled only if

  • std:: addressof ( lhs = rhs ) == std:: addressof ( lcopy ) (i.e., the assignment expression yields an lvalue referring to the left operand);
  • After evaluating lhs = rhs :
    • lhs is equal to rcopy , unless rhs is a non-const xvalue that refers to lcopy (i.e., the assignment is a self-move-assignment),
    • if rhs is a glvalue:
      • If it is a non-const xvalue, the object to which it refers is in a valid but unspecified state;
      • Otherwise, the object it refers to is not modified;

Equality preservation

Expressions declared in requires expressions of the standard library concepts are required to be equality-preserving (except where stated otherwise).

Notes

Assignment need not be a total function. In particular, if assigning to some object x can cause some other object y to be modified, then x = y is likely not in the domain of = . This typically happens if the right operand is owned directly or indirectly by the left operand (e.g., with smart pointers to nodes in a node-based data structure, or with something like std:: vector < std:: any > ).

Example

#include <atomic>
#include <concepts>
#include <string>
 
int main()
{
    // Normal basic usage, checks lvalue reference assignment
    static_assert(std::is_assignable_v<int&, int>);
    static_assert(std::assignable_from<int&, int>);
 
    static_assert(std::is_assignable_v<std::string&, std::string>);
    static_assert(std::assignable_from<std::string&, std::string>);
 
    // Fundamental types don't support assignment to an rvalue
    static_assert(!std::is_assignable_v<int, int>);
    static_assert(!std::assignable_from<int, int>);
 
    // std::assignable_from doesn't accept all valid assignment expressions:
 
    // rvalue reference assignment
    static_assert(std::is_assignable_v<std::string&&, std::string>);
    static_assert(!std::assignable_from<std::string&&, std::string>);
 
    // rvalue assignment
    static_assert(std::is_assignable_v<std::string, std::string>);
    static_assert(!std::assignable_from<std::string, std::string>);
 
    // std::atomic::operator= returns by value
    static_assert(std::is_assignable_v<std::atomic<int>&, int>);
    static_assert(!std::assignable_from<std::atomic<int>&, int>);
}

References

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

See also

checks if a type has an assignment operator for a specific argument
(class template)