
Michel MORIN schrieb:
Hi,
In some cases, Fusion Sequence cannot be used in C++0x range-based for (available on GCC 4.6 Pre-Release). For example, this code
#include <vector> #include <boost/fusion/include/vector.hpp>
int main(int argc, char* argv[]) { typedef boost::fusion::vector<int, int> sequence;
for (auto x : std::vector<sequence>()) {}
return 0; }
does not compile.
The C++0x range-based for for (auto x : std::vector<sequence>()) {} is equivalent to { auto&& rng = std::vector<sequence>(); for ( auto it_begin = begin(rng), it_end = end(rng); it_begin != it_end; ++it_begin ) {} } Note that rng has std and boost::fusion as its associated namespaces and the unqualified begin/end function call triggers ADL.
The reason for the compiler errors is that the call to begin/end is ambiguous between std::begin/end and boost::fusion::begin/end. (Also boost::fusion::begin/end tries to instanciate result_of::begin/end::<std::vector<sequence> > which leads to a compiler error.)
These compiler errors can be avoided by using SFINAE (lazy_enable_if with "is_sequence" metafunction) to boost::fusion::begin/end:
// <boost/fusion/sequence/intrinsic/begin.hpp> template <typename Sequence> inline typename lazy_enable_if< traits::is_sequence<Sequence> , typename result_of::begin<Sequence> >::type const begin(Sequence& seq) { return result_of::begin<Sequence>::call(seq); }
I attached a patch (against trunk) and a test case. The test case does not compile before applying the patch, but compiles fine after applying the patch. Joel and Christopher, what do you think about this change?
Regards, Michel
Your patch makes perfect sense to me. BTW., Mathias Gaunard created a ticket for this issue a while ago. He also proposed disabling fusion::begin/fusion::end via SFINAE. https://svn.boost.org/trac/boost/ticket/4028 -Christopher