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:
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.
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)
.
[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 tovoid
.
[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.
Change 26.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);
Change 26.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;