Why can there be const assignment operators
Asked Answered
B

1

14

With C++23 there will be

std::pair<T1, T1>::operator =( const pair &other ) const;

For me an assignment-operator operating on const-objects doesn't make any sense since the object can't be modified. Why will C++23 have this operator on pair ? And even more confusing, there's:

std::pair<T1, T1>::operator =( pair &&other ) const;

[EDIT]: This won't work because what this points to will be const:

template<typename T>
struct S
{
    void operator +=( T x ) const;
    T m_x;
};

template<typename T>
void S<T>::operator +=( T x ) const
{
    m_x += x;
}

int main( int argc, char **argv )
{
    S<int> si;
    si += 1;
}

So why is there a const-qualified assignment-operator with pair ?

Burlington answered 12/2, 2022 at 10:34 Comment(2)
It makes sense for pairs of non-const references.Oology
this happened because of open-std.org/jtc1/sc22/wg21/docs/papers/2020/…Internalcombustion
O
11

It makes sense for pairs of non-const references. Those remain assignable even when const. Consider:

#include <iostream>

template <typename T>
void foo(const T x) {x = 42;}

int main()
{
    int y = 1;
    foo<int &>(y);
    std::cout << y << '\n'; // 42
}

But why bother supporting it in std::pair?

I've recently seen an explanation somewhere on SO, but can't find the link (found it). It went along the lines of:

  • You're making a generic algorithm, and you're assigning to a function result in a template (such as to a dereferenced iterator). If the function happens to return by value, you can silently get unexpected behavior (assignment doing nothing).

  • You would like a compilation error instead, but virtually nobody &-qualifies their assignment operators.

  • Then a logical next step is to check the return type and reject non-references.

  • But you want to leave a loophole. E.g. dereferencing std::vector<bool> iterator returns (a proxy object) by value, and assigning to it should be allowed.

  • You could invent a type trait for it, but there's a clever alternative. You check if the assignment still compiles if you add const to the return type. If it doesn't, you raise a compilation error. This generalizes nicely to returning references, since adding const to them leaves the type unchanged (and still assignable, if the reference was non-const).

  • To make it work, you need to add const to assignment operators of all such types (and it was done for std::vector<bool>::reference).

  • As for why std::pair (and std::tuple) need it: iterators from std::views::zip() dereference to tuples of references, and you want to be able to assign to those tuples.

But I don't remember which standard algorithms are going to be constrained like this in C++23. Probably something in ranges...

Oology answered 12/2, 2022 at 11:10 Comment(1)
For the OP example, you'd need void operator+=(typename std::remove_reference<T>::type const& x) const to accommodate S<int&>.Choose

© 2022 - 2024 — McMap. All rights reserved.