std::assignable_from
| 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 objectlcopysuch thatdecltype((lhs))isLHS,rhs, an expression such thatdecltype((rhs))isRHS,rcopy, a distinct object that is equal torhs,
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:lhsis equal torcopy, unlessrhsis a non-const xvalue that refers tolcopy(i.e., the assignment is a self-move-assignment),- if
rhsis 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]
- 18.4.8 Concept
- C++20 standard (ISO/IEC 14882:2020):
- 18.4.8 Concept
assignable_from[concept.assignable]
- 18.4.8 Concept
See also
(C++11)(C++11)(C++11) |
checks if a type has an assignment operator for a specific argument (class template) |