Boost logo

Boost :

Subject: Re: [boost] [Fusion] begin/end ADL issues with C++0x range-based for
From: Christopher Schmidt (mr.chr.schmidt_at_[hidden])
Date: 2010-12-21 08:33:19


Joel de Guzman schrieb:
> On 12/21/2010 12:56 PM, Michel MORIN wrote:
>> Michel MORIN wrote:
>>> Better solutions would be:
>>>
>>> A. (almost the same as Jeffrey's suggestion)
>>> If boost::fusion::begin/end doesn't need to be found via ADL,
>>> then use ADL barrier technique to fusion::begin/end
>>> (i.e. defining begin/end in another namespace and pull its name
>>> in namespace fusion by using directive/declaration).
>>>
>>> B.
>>> If boost::begin/end doesn't need to be found via ADL,
>>> then use ADL barrier technique to boost::begin/end.
>>>
>>> C.
>>> Define begin/end in namespace boost for all containers and ranges
>>> which live in namespace boost (boost::array, boost::iterator_range,
>>> boost::unordered_map, etc.).
>>> For example, define begin/end for boost::array in namespace boost.
>>> Since this is very tedious work, it would be better to define some
>>> BOOST_DEFINE_BEGIN_END macro for boilerplate code generation.
>>
>> Oooops, I made a mistake!
>> Definitely, solution B is not a choice.
>> It diables Boost-interfaced range from using in range-based for.
>>
>> So let's forget about solution B.
>
> A is the only viable option, AFAIK.

Let me throw another possibility into the mix. This problem - a possible
ambiguity between fusion::begin and std::begin/boost::begin is uncommon.
In fact, only adapted boost::array's and std::array's are both fusion
sequences and ranges. To get ADL kicking in we'd actually need an array
of one of the inbuilt fusion container...

We could disable fusion::begin/fusion::end for those few types that may
collide via a new fusion extension metafunction.

Say:

  namespace boost{namespace fusion
  {
    namespace extension
    {template<typename>struct disable_begin_end_impl;}

    namespace result_of
    {template<typename>struct begin;};

    template <typename Seq>
    typename lazy_enable_if<
      mpl::and_<
        traits::is_sequence<Seq>
      , mpl::not_<extension::disable_begin_end_impl<
          typename traits::tag_of<Seq>::type
>>
>
    , result_of::begin<Seq>
>::type
    begin(Seq&& seq);
  }}

That way we'd just cripple the fusion interface for adapted arrays and
probably a minority of user-defined fusion sequences.
Ultimately, to make such types full-blown fusion sequences again, we
could offer a new (meta-)function, for example
fusion::pack/fusion::result_of::pack, which takes such a 'reduced'
fusion sequence and returns an implementation-specific object/type that
encapsulates the passed sequence and offers a full-blown fusion
interface. To do so, that wrapper forwards its fusion implementation to
the implementation of the underlying type - but always returns
mpl::false_ for extension::disable_begin_end_impl.

It's not pretty - but this approach does not break much and we'd keep
ADL, even for fusion::begin/fusion::end, in most cases.

Do I make sense?

-Christopher


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk