Boost logo

Boost :

Subject: Re: [boost] disable_if conundrum
From: Jeffrey Lee Hellrung, Jr. (jeffrey.hellrung_at_[hidden])
Date: 2011-12-05 14:39:28


On Mon, Dec 5, 2011 at 11:30 AM, Jeremiah Willcock <jewillco_at_[hidden]>wrote:

> On Mon, 5 Dec 2011, Marshall Clow wrote:
>
> I have a function that returns a pair of iterators.
>> There's also a version that takes a comparison predicate.
>>
>> template<class ForwardIterator, class Compare>
>> std::pair<ForwardIterator, ForwardIterator>
>> foo ( ForwardIterator first, ForwardIterator last );
>>
>> template<class ForwardIterator, class Compare>
>> std::pair<ForwardIterator, ForwardIterator>
>> foo ( ForwardIterator first, ForwardIterator last, Compare comp );
>>
>>
>> I want to provide a range-based version of it.
>>
>> template<class Range>
>> std::pair<typename boost::range_iterator<const Range>::type,
>> typename boost::range_iterator<const Range>::type>
>> foo ( const Range &r );
>>
>> template<class Range, class Compare>
>> std::pair<typename boost::range_iterator<const Range>::type,
>> typename boost::range_iterator<const Range>::type>
>> foo ( const Range &r, Compare comp );
>>
>> Ok. There's a problem.
>> If I call:
>> foo ( first, last )
>> I get an error, because there are two perfectly good two argument
>> candidates.
>>
>> Fine. Been there, seen that. I can use disable_if to make sure that the
>> second range based version is only "active" when the arguments are
>> different types. It's verbose, but it (usually) works
>>
>> template<class Range, class Compare>
>> typename boost::disable_if_c<boost::is_**same<Range,
>> Compare>::value,
>> std::pair<typename boost::range_iterator<const
>> Range>::type, typename boost::range_iterator<const Range>::type>
>> >::type
>> foo ( const Range &r, Compare comp );
>>
>> But this time it does not! I get a compile error telling me that the
>> compiler can't deal with boost::range_iterator<XXX>::**type, when XXX =
>> some random iterator. It seems that the compiler wants to evaluate all the
>> parameters of disable_if_c before deciding whether or not to SFINAE it (I
>> guess that's not unreasonable, but it's not what I want)
>>
>> Apparently, all the other times that I did this, the return type of the
>> function was not a dependent type of the template arguments.
>>
>> Any suggestions for a workaround here?
>>
>
> Look at lazy_disable_if -- it doesn't get the nested "type" member of the
> type you give it unless the condition evaluates to false.
>

Just to supplement: also use an extra level of indirection, a metafunction
that maps Range to the return type of foo. So will look like
boost::lazy_disable_if_c< condition, foo_result< Range > >::type.

- Jeff


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