Boost logo

Boost :

Subject: [boost] [Fusion] begin/end ADL issues with C++0x range-based for
From: Michel MORIN (mimomorin_at_[hidden])
Date: 2010-12-18 06:35:40


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;
        ) {}
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
          , 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?


Boost list run by bdawes at, gregod at, cpdaniel at, john at