4

I am using heavily BOOST_FOREACH for iteration over containers, and since I moved to c++0x recently, I thought I could replace BOOST_FOREACH with range-based for construct. The following piece of code

#include<vector>
#include<boost/shared_ptr.hpp>
#include<boost/range.hpp>
using std::vector; using boost::shared_ptr;
class Node;
int main(void){
   vector<shared_ptr<Node>> nodes;
   for(const shared_ptr<Node>& n: nodes);
}

does not compile with gcc 4.6, leading to

error: call of overloaded 'end(std::vector<boost::shared_ptr<Node> >&)' is ambiguous
note: candidates are:
/usr/include/c++/4.6/bits/range_access.h:78:5: note: decltype (__cont->end()) std::end(const _Container&) [with _Container = std::vector<boost::shared_ptr<Node> >, decltype (__cont->end()) = __gnu_cxx::__normal_iterator<const boost::shared_ptr<Node>*, std::vector<boost::shared_ptr<Node> > >]
/usr/include/c++/4.6/bits/range_access.h:68:5: note: decltype (__cont->end()) std::end(_Container&) [with _Container = std::vector<boost::shared_ptr<Node> >, decltype (__cont->end()) = __gnu_cxx::__normal_iterator<boost::shared_ptr<Node>*, std::vector<boost::shared_ptr<Node> > >]
/usr/include/boost/range/end.hpp:103:47: note: typename boost::range_iterator<const T>::type boost::end(const T&) [with T = std::vector<boost::shared_ptr<Node> >, typename boost::range_iterator<const T>::type = __gnu_cxx::__normal_iterator<const boost::shared_ptr<Node>*, std::vector<boost::shared_ptr<Node> > >]
/usr/include/boost/range/end.hpp:92:41: note: typename boost::range_iterator<C>::type boost::end(T&) [with T = std::vector<boost::shared_ptr<Node> >, typename boost::range_iterator<C>::type = __gnu_cxx::__normal_iterator<boost::shared_ptr<Node>*, std::vector<boost::shared_ptr<Node> > >]

Is there a way to avoid such ambiguity, or is range-based for simply unusable in such situation?

1 Answer 1

3

Tricky. You're pulling in std::end and boost::end because the associated namespaces of std::vector<boost::shared_ptr> are both std and boost. Both are templates that match.

However, a non-template end() would be an even better match. So, just provide your own:

inline std::vector<boost::shared_ptr<Node> >::iterator
   end(std::vector<boost::shared_ptr<Node> > vsn&)
{
  return std::end(vsn); 
}
Sign up to request clarification or add additional context in comments.

7 Comments

Wow, thanks! I tried a minimal exmaple and it breaks only if I #include<boost/range.hpp>. I will edit the question to show it.
Hm... It would be better to have something more universal, as here for each containers type 4 iterators (begin, const begin, end, const end) have to be wrapped that way.Hopefully boost::serialization will support std::shared_ptr soon and I will be able to abandon boost::shared_ptr :-|
@eudoxos: This issue will be fixed in future Boost releases.
Was that original problem only because of the using directives, or would that always have been resolved wrongly no matter what?
Additional information: gcc 4.6 is in error. The range-based for-loop was changed to avoid this problem just this past March (probably after gcc 4.6 was set in concrete). The compiler should first check vector for member begin and end and use those if found (which it will in this example). Only if the member begin and end are not found will it resort to ADL.
|

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.