ambiguity between std::begin/end and boost::begin/end in gcc 4.6
The following code fails to compile with a development build of gcc 4.6: #include <boost/range/adaptor/reversed.hpp> #include <vector> int main() { std::vector<int> v; for (int i : v | boost::adaptors::reversed); return 0; } The errors are: reversed.cpp: In function âint main()â: reversed.cpp:16:39: error: call of overloaded âbegin(boost::range_detail::reverse_range<std::vector<int> >&)â is ambiguous reversed.cpp:16:39: note: candidates are: /usr/local/lib/gcc/i686-pc-linux-gnu/4.6.0/../../../../include/c++/4.6.0/bits/range_access.h:56:5: note: decltype (__cont->begin()) std::begin(const _Container&) [with _Container = boost::range_detail::reverse_range<std::vector<int> >, decltype (__cont->begin()) = boost::reverse_iterator<__gnu_cxx::__normal_iterator<int*, std::vector<int> > >] /usr/local/lib/gcc/i686-pc-linux-gnu/4.6.0/../../../../include/c++/4.6.0/bits/range_access.h:46:5: note: decltype (__cont->begin()) std::begin(_Container&) [with _Container = boost::range_detail::reverse_range<std::vector<int> >, decltype (__cont->begin()) = boost::reverse_iterator<__gnu_cxx::__normal_iterator<int*, std::vector<int> > >] /home/nridge/lib/boost/boost/range/begin.hpp:107:61: note: typename boost::range_iterator<const T>::type boost::begin(const T&) [with T = boost::range_detail::reverse_range<std::vector<int> >, typename boost::range_iterator<const T>::type = boost::reverse_iterator<__gnu_cxx::__normal_iterator<int*, std::vector<int> > >] /home/nridge/lib/boost/boost/range/begin.hpp:96:55: note: typename boost::range_iterator<C>::type boost::begin(T&) [with T = boost::range_detail::reverse_range<std::vector<int> >, typename boost::range_iterator<C>::type = boost::reverse_iterator<__gnu_cxx::__normal_iterator<int*, std::vector<int> > >] reversed.cpp:16:39: error: call of overloaded âend(boost::range_detail::reverse_range<std::vector<int> >&)â is ambiguous reversed.cpp:16:39: note: candidates are: /usr/local/lib/gcc/i686-pc-linux-gnu/4.6.0/../../../../include/c++/4.6.0/bits/range_access.h:76:5: note: decltype (__cont->end()) std::end(const _Container&) [with _Container = boost::range_detail::reverse_range<std::vector<int> >, decltype (__cont->end()) = boost::reverse_iterator<__gnu_cxx::__normal_iterator<int*, std::vector<int> > >] /usr/local/lib/gcc/i686-pc-linux-gnu/4.6.0/../../../../include/c++/4.6.0/bits/range_access.h:66:5: note: decltype (__cont->end()) std::end(_Container&) [with _Container = boost::range_detail::reverse_range<std::vector<int> >, decltype (__cont->end()) = boost::reverse_iterator<__gnu_cxx::__normal_iterator<int*, std::vector<int> > >] /home/nridge/lib/boost/boost/range/end.hpp:103:61: note: typename boost::range_iterator<const T>::type boost::end(const T&) [with T = boost::range_detail::reverse_range<std::vector<int> >, typename boost::range_iterator<const T>::type = boost::reverse_iterator<__gnu_cxx::__normal_iterator<int*, std::vector<int> > >] /home/nridge/lib/boost/boost/range/end.hpp:92:55: note: typename boost::range_iterator<C>::type boost::end(T&) [with T = boost::range_detail::reverse_range<std::vector<int> >, typename boost::range_iterator<C>::type = boost::reverse_iterator<__gnu_cxx::__normal_iterator<int*, std::vector<int> > >] The problem is caused by an ambiguity between std::begin/end (new in C++0x) and boost::begin/end. I've found this bug: https://svn.boost.org/trac/boost/ticket/4099 and this thread: http://groups.google.com/group/boost-devel-archive/browse_thread/thread/f97a... which mention similar issues, but neither of them seem to address/fix the issue in Boost.Range. Regards, Nate.
On Mon, Dec 27, 2010 at 4:25 AM, Nathan Ridge <zeratul976@hotmail.com>wrote:
The following code fails to compile with a development build of gcc 4.6:
#include <boost/range/adaptor/reversed.hpp> #include <vector> int main() { std::vector<int> v; for (int i : v | boost::adaptors::reversed); return 0; }
The errors are:
reversed.cpp: In function âint main()â: reversed.cpp:16:39: error: call of overloaded âbegin(boost::range_detail::reverse_range<std::vector<int> >&)â is ambiguous reversed.cpp:16:39: note: candidates are: /usr/local/lib/gcc/i686-pc-linux-gnu/4.6.0/../../../../include/c++/4.6.0/bits/range_access.h:56:5: note: decltype (__cont->begin()) std::begin(const _Container&) [with _Container = boost::range_detail::reverse_range<std::vector<int> >, decltype (__cont->begin()) = boost::reverse_iterator<__gnu_cxx::__normal_iterator<int*, std::vector<int>
] /usr/local/lib/gcc/i686-pc-linux-gnu/4.6.0/../../../../include/c++/4.6.0/bits/range_access.h:46:5: note: decltype (__cont->begin()) std::begin(_Container&) [with _Container = boost::range_detail::reverse_range<std::vector<int> >, decltype (__cont->begin()) = boost::reverse_iterator<__gnu_cxx::__normal_iterator<int*, std::vector<int> ] /home/nridge/lib/boost/boost/range/begin.hpp:107:61: note: typename boost::range_iterator<const T>::type boost::begin(const T&) [with T = boost::range_detail::reverse_range<std::vector<int> >, typename boost::range_iterator<const T>::type = boost::reverse_iterator<__gnu_cxx::__normal_iterator<int*, std::vector<int> ] /home/nridge/lib/boost/boost/range/begin.hpp:96:55: note: typename boost::range_iterator<C>::type boost::begin(T&) [with T = boost::range_detail::reverse_range<std::vector<int> >, typename boost::range_iterator<C>::type = boost::reverse_iterator<__gnu_cxx::__normal_iterator<int*, std::vector<int> ] reversed.cpp:16:39: error: call of overloaded âend(boost::range_detail::reverse_range<std::vector<int> >&)â is ambiguous reversed.cpp:16:39: note: candidates are: /usr/local/lib/gcc/i686-pc-linux-gnu/4.6.0/../../../../include/c++/4.6.0/bits/range_access.h:76:5: note: decltype (__cont->end()) std::end(const _Container&) [with _Container = boost::range_detail::reverse_range<std::vector<int> >, decltype (__cont->end()) = boost::reverse_iterator<__gnu_cxx::__normal_iterator<int*, std::vector<int> > >] /usr/local/lib/gcc/i686-pc-linux-gnu/4.6.0/../../../../include/c++/4.6.0/bits/range_access.h:66:5: note: decltype (__cont->end()) std::end(_Container&) [with _Container = boost::range_detail::reverse_range<std::vector<int> >, decltype (__cont->end()) = boost::reverse_iterator<__gnu_cxx::__normal_iterator<int*, std::vector<int> > >] /home/nridge/lib/boost/boost/range/end.hpp:103:61: note: typename boost::range_iterator<const T>::type boost::end(const T&) [with T = boost::range_detail::reverse_range<std::vector<int> >, typename boost::range_iterator<const T>::type = boost::reverse_iterator<__gnu_cxx::__normal_iterator<int*, std::vector<int> ] /home/nridge/lib/boost/boost/range/end.hpp:92:55: note: typename boost::range_iterator<C>::type boost::end(T&) [with T = boost::range_detail::reverse_range<std::vector<int> >, typename boost::range_iterator<C>::type = boost::reverse_iterator<__gnu_cxx::__normal_iterator<int*, std::vector<int> ]
The problem is caused by an ambiguity between std::begin/end (new in C++0x) and boost::begin/end.
I don't believe that it should be ambiguous since all of the calls to begin/end are qualified. See the relevant code: explicit reversed_range( R& r ) : base( iterator(boost::end(r)), iterator(boost::begin(r)) ) ^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^ { } Hence the error reporting that this is ambiguous with std::begin/std::end is likely a defect in either compiler lookup or a missing qualified call to begin/end in the standard library. I've found this bug: https://svn.boost.org/trac/boost/ticket/4099
and this thread: http://groups.google.com/group/boost-devel-archive/browse_thread/thread/f97a...
This ticket is somewhat different. Boost.Algorithm was not qualifying the calls to begin/end and hence with argument dependent lookup there was ambiguity.
which mention similar issues, but neither of them seem to address/fix the issue in Boost.Range.
There have not been any issues with missing qualification of begin/end calls in Boost.Range hence no ticket.
Regards, Nate.
You might get a quicker response from the GCC team, but I'm happy to look into this issue if you provide the exact version of GCC and library version you are using. It will, of course, take me a while since I'll have to setup the compiler and environment. You might want to take a look at the relevant standard library, or the compiler implementation of the new 'for' syntax. I suspect there might be an unqualified call to begin() and/or end(). Regards, Neil Groves
Neil Groves wrote:
You might get a quicker response from the GCC team, but I'm happy to look into this issue if you provide the exact version of GCC and library version you are using. It will, of course, take me a while since I'll have to setup the compiler and environment.
You might want to take a look at the relevant standard library, or the compiler implementation of the new 'for' syntax. I suspect there might be an unqualified call to begin() and/or end().
For this issue, there is some information in the following thread: (a patch and a test case are also provided in the thread.) http://article.gmane.org/gmane.comp.lib.boost.devel/211863 If we are allowed to break existing codes that rely on ADL to find boost::begin/end, this issue can be easily resolved by putting boost::begin/end into an ADL-barrier namespace and bringing them into namespace boost with a using directive. Regards, Michel
On Mon, Dec 27, 2010 at 3:37 PM, Michel MORIN <mimomorin@gmail.com> wrote:
Neil Groves wrote:
You might get a quicker response from the GCC team, but I'm happy to look into this issue if you provide the exact version of GCC and library version you are using. It will, of course, take me a while since I'll have to setup the compiler and environment.
You might want to take a look at the relevant standard library, or the compiler implementation of the new 'for' syntax. I suspect there might be an unqualified call to begin() and/or end().
For this issue, there is some information in the following thread: (a patch and a test case are also provided in the thread.) http://article.gmane.org/gmane.comp.lib.boost.devel/211863
If we are allowed to break existing codes that rely on ADL to find boost::begin/end, this issue can be easily resolved by putting boost::begin/end into an ADL-barrier namespace and bringing them into namespace boost with a using directive.
None of our boost code should be using unqualified calls to begin/end. The Boost.Range design explicitly provided range_begin and range_end as the function names to be found via ADL so that everyone could use qualified boost::begin and boost::end calls. boost::begin and boost::end are explicitly qualified throughout Boost.Range and hence the ambiguous call isn't coming from Boost.Range. Please see http://www.boost.org/doc/libs/1_45_0/libs/range/doc/html/range/reference/ext... the relevant documentation. Hence we can certainly break code that is erroneously relying on ADL for begin/end to be found via ADL. However in this case I have yet to understand the nature of the underlying problem, because there isn't an obvious unqualified call to begin/end. The reverse adaptor uses qualified calls that can't possibly be ambiguous with std::begin/end. I haven't yet checked to see if unqualified calls to begin/end are intended to be used as an extension mechanism for the next C++ standard. I shall put begin and end in an ADL barrier namespace anyhow, since these are explicitly designed to be qualified when called.
Regards, Michel
Regards, Neil Groves
From: neil@grovescomputing.com To: boost-users@lists.boost.org Subject: Re: [Boost-users] ambiguity between std::begin/end and boost::begin/end in gcc 4.6
However in this case I have yet to understand the nature of the underlying problem, because there isn't an obvious unqualified call to begin/end. The reverse adaptor uses qualified calls that can't possibly be ambiguous with std::begin/end. I haven't yet checked to see if unqualified calls to begin/end are intended to be used as an extension mechanism for the next C++ standard.
The unqualified call to begin/end comes from the range-based for loop. Quoting from the C++0x Standard Section 6.5.4 (http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2010/n3225.pdf): ------------------------------------------------------------------------ For a range-based for statement of the form for ( for-range-declaration : expression ) statement let range-init be equivalent to the expression surrounded by parentheses:89 ( expression ) and for a range-based for statement of the form for ( for-range-declaration : braced-init-list ) statement let range-init be equivalent to the braced-init-list. In each case, a range-based for statement is equivalent to { auto && __range = range-init; for ( auto __begin = begin-expr, __end = end-expr; __begin != __end; ++__begin ) { for-range-declaration = *__begin; statement } } where __range, __begin, and __end are variables defined for exposition only, and _RangeT is the type of the expression, and begin-expr and end-expr are determined as follows:. — if _RangeT is an array type, begin-expr and end-expr are __range and __range + __bound, respectively, where __bound is the array bound. If _RangeT is an array of unknown size or an array of incomplete type, the program is ill-formed. — otherwise, begin-expr and end-expr are begin(__range) and end(__range), respectively, where begin and end are looked up with argument-dependent lookup (3.4.2). For the purposes of this name lookup, namespace std is an associated namespace. ------------------------------------------------------------------------ So "std" is an associated namespace because the standard says so, and "boost" is an associated namespace because the type being iterated over is boost::reverse_range<T>, and so ADL finds both std::begin/end and boost::begin/end. Regards, Nate.
Neil Groves wrote:
However in this case I have yet to understand the nature of the underlying problem, because there isn't an obvious unqualified call to begin/end. The reverse adaptor uses qualified calls that can't possibly be ambiguous with std::begin/end. I haven't yet checked to see if unqualified calls to begin/end are intended to be used as an extension mechanism for the next C++ standard.
Here is the standard: Range-Based For Loop Wording (Without Concepts) http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2009/n2930.html Its summary is: A range-based for for (auto x : range_expr) { // do something } is equivalent to { // Special rule: namespace std is added to rng's associated namespaces auto&& rng = range_expr; for ( // Note: unqualified begin/end function call auto it = begin(rng), it_end = end(rng); it != it_end; ++it ) { auto x = *it; // do something } } Note that rng has namespace std as its associated namespaces and the unqualified begin/end function call triggers ADL.
I shall put begin and end in an ADL barrier namespace anyhow, since these are explicitly designed to be qualified when called.
That would be Great, Neil! This is an important issue. Regards, Michel
participants (3)
-
Michel MORIN
-
Nathan Ridge
-
Neil Groves