Opened 13 years ago

Last modified 9 years ago

#4028 reopened Bugs

fusion::begin and fusion::end lead to problems with ADL-based begin and end functions for ranges

Reported by: Mathias Gaunard Owned by: Joel de Guzman
Milestone: To Be Determined Component: fusion
Version: Boost 1.42.0 Severity: Problem
Keywords: ADL range begin end Cc: mateusz@…

Description

In C++0x, begin and end for ranges (that extract the beginning iterator and the past-the-end one, respectively) are to be found through ADL. This causes problems when fusion is an associated namespace (as for example in the case iterator_range< some_iterator< fusion::vector<> > > ), since the begin and end of the fusion namespace will be considered by ADL, and that results in an error because a range is not a fusion sequence.

I see two (three) solutions:

  • Mask fusion::begin and fusion::end with SFINAE so that they are only available if the argument is a fusion sequence. That means however that we can't have a fusion sequence that is at the same time a range, even though this could have some uses.
  • Rename fusion::begin and fusion::end to something else.

(- Ask the standard people to reconsider)

Change History (11)

comment:1 by anonymous, 12 years ago

I believe this is not a bug. not a boost bug anyway.

did you use GCC for this? up until GCC 4.4 it had a bug that caused ADL lookups in namespaces that are only referred to by template argument.

just because the "fusion" namespace appears in a template argument should not cause an ADL lookup in that namespace, if none of the arguments are in that namespace.

fixed in GCC 4.5 and other compilers.

comment:2 by Steven Watanabe, 12 years ago

I'm afraid I don't understand why this should be considered a GCC bug.

3.4.2 says:

If T is a template-id, its associated namespaces and classes are the namespace in which the template is defined; for member templates, the member template’s class; the namespaces and classes associated with the types of the template arguments provided for template type parameters (excluding template template parameters); the namespaces in which any template template arguments are defined; and the classes in which any member templates used as template template arguments are defined. [Note: nontype template arguments do not contribute to the set of associated namespaces. ]

(emphasis added)

comment:3 by anonymous, 12 years ago

I'm not familiar with specification details or whether there has been a defect report regarding this. All I can say is that, IF we're talking about the same issue, 2 compilers besides GCC don't associate namespaces of template arguments. and that I have reported this as a bug to GCC. reply to my report: fixed in 4.5, not a regression.

here's a test case that triggers the bug (or non-bug) up to GCC 4.4:

namespace mpl{

class apply{}; class vector{};

}

template<class T> void apply(T const &){}

template<class T> class A{};

int main(){

A<mpl::vector> a; apply(a);

}

comment:4 by anonymous, 12 years ago

reconsidering, this seems like 2 different issues to me. I think GCC rightfully associates namespaces of template arguments. the bug here was that it didn't omit the type "apply" when it was looking for an ADL function.

as fusion::begin and std::begin are both functions this seems to be unrelated.

comment:5 by Christopher Schmidt, 12 years ago

Resolution: fixed
Status: newclosed

(In [67352]) Fusion: mask fusion::begin/fusion::end with SFINAE, fixes #4028

comment:6 by Mathias Gaunard, 12 years ago

Resolution: fixed
Status: closedreopened

While a useful fix, note that still doesn't fix the underlying problem.

Here is a testcase that still fails:

#include <boost/array.hpp>
#include <boost/fusion/container/vector.hpp>
#include <boost/fusion/sequence/intrinsic/end.hpp>
#include <boost/fusion/adapted/array.hpp>
#include <boost/range.hpp>

int main()
{
    boost::array<boost::fusion::vector<>, 42> foo;
    begin(foo); // ambiguous, boost::begin or boost::fusion::begin
}

Therefore I suggest the bug be left open.

comment:7 by anonymous, 12 years ago

Milestone: Boost 1.43.0To Be Determined

What can we do?

I am not in favour of renaming fusion::begin/fusion::end - that would break a lot of code. We could remove the code to adapt arrays, or refactor it to a new facility that would adapt arrays by name (just like the named BOOST_FUSION_ADAPT_STRUCT_NAMED) - but this would break a lot of code as well. This does not solve the underlying problem of ambiguity either.

I suggest adding a note in the documentation that points out this issue and proposes to explicitly namespace-qualify calls to fusion::begin/fusion::end in generic user code.

comment:8 by anonymous, 12 years ago

I don't think we can do anything about that problem without breaking changes in Fusion.

Nevertheless the problem still exists in some cases, maybe it should be marked as partial wontfix ?

Forcing users to qualify begin and end doesn't solve the problem, since the C++0x for-loop construct calls those functions unqualified and relies on ADL. The real solution, to me, would be for the standard to reconsider the use of begin/end through ADL, but it's now too late for that.

comment:9 by anonymous, 12 years ago

I believe the only solution we have is to use an ADL barrier. E.g.

#include <boost/array.hpp>
#include <boost/fusion/container/vector.hpp>
#include <boost/fusion/sequence/intrinsic/end.hpp>
#include <boost/fusion/adapted/array.hpp>
#include <boost/range.hpp>

namespace boost { namespace fusion {

    namespace adl_barrier
    {
        struct xx {};
    }
    using ::boost::fusion::adl_barrier::xx;
}}

int main()
{
    boost::array<boost::fusion::xx, 42> foo;
    begin(foo); 
}
Last edited 9 years ago by Mateusz Loskot (previous) (diff)

comment:10 by Mateusz Loskot, 9 years ago

Cc: mateusz@… added

comment:11 by Mateusz Loskot, 9 years ago

I have added basic adoption of std::array as Boost.Fusion sequence, #8241, and I'm interested in solving the ADL issue.

By the way, for easy reference, here is the old thread related to this issue: Fusion begin/end ADL issues with C++0x range-based for

Last edited 9 years ago by Mateusz Loskot (previous) (diff)
Note: See TracTickets for help on using tickets.