This page is a snapshot from the LWG issues list, see the Library Active Issues List for more information and the meaning of C++17 status.

### 2133. Attitude to overloaded comma for iterators

Section: 16.4.6.4 [global.functions] Status: C++17 Submitter: Yakov Galka Opened: 2012-01-25 Last modified: 2017-07-30

Priority: 3

View all other issues in [global.functions].

View all issues with C++17 status.

Discussion:

16.4.6.4 [global.functions] says

> Unless otherwise specified, global and non-member functions in the standard library shall not use functions from another namespace which are found through argument-dependent name lookup (3.4.2).

This sounds clear enough. There are just two problems:

1. Both implementations I tested (VS2005 and GCC 3.4.3) do unqualified calls to the comma operator in some parts of the library with operands of user-defined types.

2. The standard itself does this in the description of some algorithms. E.g. `uninitialized_copy` is defined as:

   > Effects:

   > >     for (; first != last; ++result, ++first)
   > >       ::new (static_cast<void*>(&*result))
   > >         typename iterator_traits<ForwardIterator>::value_type(*first);

If understood literally, it is required to call `operator,(ForwardIterator, InputIterator)`.

For detailed discussion with code samples see here.

Proposal:

1. Add an exception to the rule in 16.4.6.4 [global.functions] by permitting the implementation to call the comma operator as much as it wants to. I doubt we want this. or
2. Fix the description of the said algorithms and perhaps add a note to 16.4.6.4 [global.functions] that brings attention of the implementers to avoid this pitfall.

[2013-03-15 Issues Teleconference]

Moved to Open.

There are real questions here, that may require a paper to explore and answer properly.

[2014-05-18, Daniel comments and suggests concrete wording]

Other issues, such as 2114 already follow a similar spirit as the one suggested by bullet 2 of the issue submitter. I assert that consideration of possible user-provided overloads of the comma-operator were not intended by the original wording and doing so afterwards would unnecessarily complicate a future conceptualization of the library and would needlessly restrict implementations.

I don't think that a paper is needed to solve this issue, there is a simply way to ensure that the code-semantics excludes consideration of user-provided comma operators. The provided wording below clarifies this by explicitly casting the first argument of the operator to `void`.

[2015-05, Lenexa]

DK: is putting it in the middle the right place for it?
STL: either works, but visually putting it in the middle is clearer, and for "++it1, ++i2, ++it3" it needs to be done after the second comma, so "++it1, (void) ++i2, (void) ++it3" is better than "(void) ++it1, ++i2, (void) ++it3"
ZY: for `INVOKE` yesterday we used `static_cast<void>` but here we're using C-style cast, why?
STL: for `INVOKE` I want to draw attention that there's an intentional coercion to `void` because that's the desired type. Here we only do it because that's the best way to prevent the problem, not because we specifically want a `void` type.
Move to Ready: 9 in favor, none opposed, 1 abstention

Proposed resolution:

This wording is relative to N3936.

1. Change 27.11.5 [uninitialized.copy] as indicated:

   >     template <class InputIterator, class ForwardIterator>
   >       ForwardIterator uninitialized_copy(InputIterator first, InputIterator last,
   >                                          ForwardIterator result);

   > > -1- Effects:

   > > >     for (; first != last; ++result, (void) ++first)
   > > >       ::new (static_cast<void*>(&*result))
   > > >         typename iterator_traits<ForwardIterator>::value_type(*first);

   > > […]

   >     template <class InputIterator, class Size,class ForwardIterator>
   >       ForwardIterator uninitialized_copy_n(InputIterator first, Size n,
   >                                            ForwardIterator result);

   > > -3- Effects:

   > > >     for (; n > 0; ++result, (void) ++first, --n)
   > > >       ::new (static_cast<void*>(&*result))
   > > >         typename iterator_traits<ForwardIterator>::value_type(*first);

2. Change 27.8.11 [alg.lex.comparison] p3 as indicated:

   >     template<class InputIterator1, class InputIterator2>
   >       bool
   >         lexicographical_compare(InputIterator1 first1, InputIterator1 last1,
   >                                 InputIterator2 first2, InputIterator2 last2);
   >     template<class InputIterator1, class InputIterator2, class Compare>
   >       bool
   >         lexicographical_compare(InputIterator1 first1, InputIterator1 last1,
   >                                 InputIterator2 first2, InputIterator2 last2,
   >                                 Compare comp);

   > > -3- Remarks: […]

   > > >     for ( ; first1 != last1 && first2 != last2 ; ++first1, (void) ++first2) {
   > > >       if (*first1 < *first2) return true;
   > > >       if (*first2 < *first1) return false;
   > > >     }
   > > >     return first1 == last1 && first2 != last2;