1133. Does N2844 break current specification of list::splice?

Section: 23.3.7.6 [forward.list.ops], 23.3.9.5 [list.ops] Status: C++11 Submitter: Alisdair Meredith Opened: 2009-05-09 Last modified: 2023-02-07

Priority: Not Prioritized

View all other issues in [forward.list.ops].

View all issues with C++11 status.

Discussion:

IIUC, N2844 means that lvalues will no longer bind to rvalue references. Therefore, the current specification of list::splice (list operations 23.3.9.5 [list.ops]) will be a breaking change of behaviour for existing programs. That is because we changed the signature to swallow via an rvalue reference rather than the lvalue reference used in 03.

Retaining this form would be safer, requiring an explicit move when splicing from lvalues. However, this will break existing programs. We have the same problem with forward_list, although without the risk of breaking programs so here it might be viewed as a positive feature.

The problem signatures:

void splice_after(const_iterator position, forward_list<T,Alloc>&& x);
void splice_after(const_iterator position, forward_list<T,Alloc>&& x,
                  const_iterator i);
void splice_after(const_iterator position, forward_list<T,Alloc>&& x,
                  const_iterator first, const_iterator last);

void splice(const_iterator position, list<T,Alloc>&& x);
void splice(const_iterator position, list<T,Alloc>&& x,
            const_iterator i);
void splice(const_iterator position, list<T,Alloc>&& x,
            const_iterator first, const_iterator last);

Possible resolutions:

Option A. Add an additional (non-const) lvalue-reference overload in each case

Option B. Change rvalue reference back to (non-const) lvalue-reference overload in each case

Option C. Add an additional (non-const) lvalue-reference overload in just the std::list cases

I think (B) would be very unfortunate, I really like the forward_list behaviour in (C) but feel (A) is needed for consistency.

My actual preference would be NAD, ship with this as a breaking change as it is a more explicit interface. I don't think that will fly though!

See the thread starting with c++std-lib-23725 for more discussion.

[ 2009-10-27 Christopher Jefferson provides proposed wording for Option C. ]

[ 2009-12-08 Jonathan Wakely adds: ]

As Bill Plauger pointed out, list::merge needs similar treatment.

[ Wording updated. ]

[ 2009-12-13 Moved to Tentatively Ready after 5 positive votes on c++std-lib. ]

Proposed resolution:

In 23.3.9 [list]

Add lvalue overloads before rvalue ones:

void splice(const_iterator position, list<T,Allocator>& x);
void splice(const_iterator position, list<T,Allocator>&& x);
void splice(const_iterator position, list<T,Allocator>& x, const_iterator i);
void splice(const_iterator position, list<T,Allocator>&& x, const_iterator i);
void splice(const_iterator position, list<T,Allocator>& x,
            const_iterator first, const_iterator last);
void splice(const_iterator position, list<T,Allocator>&& x,
            const_iterator first, const_iterator last);
void merge(list<T,Allocator>& x);
template <class Compare> void merge(list<T,Allocator>& x, Compare comp);
void merge(list<T,Allocator>&& x);
template <class Compare> void merge(list<T,Allocator>&& x, Compare comp);

In 23.3.9.5 [list.ops], similarly add lvalue overload before each rvalue one:

(After paragraph 2)

void splice(const_iterator position, list<T,Allocator>& x);
void splice(const_iterator position, list<T,Allocator>&& x);

(After paragraph 6)

void splice(const_iterator position, list<T,Allocator>& x, const_iterator i);
void splice(const_iterator position, list<T,Allocator>&& x, const_iterator i);

(After paragraph 10)

void splice(const_iterator position, list<T,Allocator>& x,
            const_iterator first, const_iterator last);
void splice(const_iterator position, list<T,Allocator>&& x,
            const_iterator first, const_iterator last);

In 23.3.9.5 [list.ops], after paragraph 21

void merge(list<T,Allocator>& x);
template <class Compare> void merge(list<T,Allocator>& x, Compare comp);
void merge(list<T,Allocator>&& x);
template <class Compare> void merge(list<T,Allocator>&& x, Compare comp);