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 ?

2

1 Answer 1

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...

Sign up to request clarification or add additional context in comments.

1 Comment

For the OP example, you'd need void operator+=(typename std::remove_reference<T>::type const& x) const to accommodate S<int&>.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.