6

I've got a few questions about std::assignable_from behavior. Cppreference suggests the following implementation for it:

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>;
  };

The question is what is the purpose of the second requirement, i.e.,

std::common_reference_with<
    const std::remove_reference_t<LHS>&,
    const std::remove_reference_t<RHS>&>

Could anyone elaborate this requirement and provide some examples on it?

If the context matters, I'm trying to learn about C++20 concepts from this post. My question is related to one specific example from it:

template <typename D, std::integral T>
requires std::assignable_from<D, T>
void assign_the_thing(D& dest, T&& x)
{
    dest = std::forward<T>(x);
}

However, I doubt if this is a right way to use assignable_from, anyway.

T.C.
  • 133,968
  • 17
  • 288
  • 421
Baykov Nikita
  • 608
  • 4
  • 11
  • Does this answer your question? [What is the purpose of C++20 std::common\_reference?](https://stackoverflow.com/questions/59011331/what-is-the-purpose-of-c20-stdcommon-reference) – Nicol Bolas Feb 09 '20 at 16:08
  • @NicolBolas Sorry, but I didn't get the idea. It is not clear what is the result of `common_reference_with` in the case described by Eric Niebler, and how it is related to the assignment operator. – Baykov Nikita Feb 09 '20 at 17:22
  • 1
    The `common_reference_with...` requirement implies non sensical results: [here](https://godbolt.org/z/rNfoPd). In this exemple code, assignable_from fails because B is convertible to A and A is convertible to B. So at least, the name of this concept is misleading. – Oliv Feb 09 '20 at 19:47
  • There is the same mistake in swappable_with concept!! But it was worst in the TS. – Oliv Feb 09 '20 at 20:33

1 Answers1

4

The common_reference_with requirement basically ensures that there's some common intermediate type through which we can reason about the meaning of mixed-type assignment. It enables the semantic requirement that after an assignment "lhs is equal to rcopy", because we otherwise can't really say what it means for two values of different types to be equal.


Also, the definition we give for concepts are generally not "possible implementations". They are exactly what the working paper says.

T.C.
  • 133,968
  • 17
  • 288
  • 421
  • 1
    Two value of different types can be equals for exemple if their associated types are 2 different representation of the same categories. In such case type A is convertible to B and B is convertible to A. The consequence of this symmetric convertibility is that assignable_from will fail... this is non sensical. – Oliv Feb 10 '20 at 16:18
  • 1
    @T.C., thank you for answer! Unfortunately, it is still not clear to me. Now I have even more questions. You said that the common intermediate type is required for equality checking. I can't really see how it helps. Is it some kind of replacement for the equality requirement? If not, then how the equality checking can be expressed in terms of common reference type? Why `const std::remove_reference_t&` is used instead of `const LHS&`. Why we have to make `common_reference_with` arguments `const`-qualified? – Baykov Nikita Feb 10 '20 at 16:23
  • This is more like a defect than feature. I guess `` should be avoided in favor of good old ``. – Red.Wave May 30 '23 at 14:51