Boost logo

Boost :

Subject: Re: [boost] [range] [general] making member functions SFINAE-friendly
From: Andrey Semashev (andrey.semashev_at_[hidden])
Date: 2013-02-18 01:36:55


On Mon, Feb 18, 2013 at 9:30 AM, Nathan Ridge <zeratul976_at_[hidden]> wrote:
>
> Hi,
>
> I recently came across a request to make iterator_range<I>::size()
> SFINAE-friendly [1].
>
> The respect in which it is not currently SFINAE-friendly is that
> it is only applicable to instantiations where I is a random-access
> iterator, but it is defined for all instantiations, and fails with
> a static assertion if I is not random-access. This makes it
> impossible to use SFINAE techniques to detect whether "r.size()"
> is valid where r is some iterator_range.
>
> The suggested workaround is to give iterator_range a base class,
> specialize this base class for random-access iterators, and only
> define size() in this specialization.
>
> I think this deficiency and workaround can be generalized to any
> template class 'C<T>' with a member function 'foo' that is only
> applicable for a subset of valid template arguments for 'T'. I am
> curious what the Boost community thinks about applying this
> workaround (factoring out the member function into a base class)
> as a general rule in such situations? Is making the member
> function SFINAE-friendly worth the decrease in readability? Are
> there other disadvantages to this workaround?
>
> Are there alternative ways of making such a function SFINAE-
> friendly that don't require introducing a base class?
>
> Finally, if the consensus is that such a workaround is not
> justified in general, is there any reason it should be justified
> specifically for iterator_range<I>::size()?

Could you share a use case that requires to depend on size()
specifically rather than the iterator category?

IMHO, this approach doesn't look like worth the effort. Currently,
size() is only defined for random access iterators but technically it
is also valid for bidirectional and forward iterators if implemented
in terms of std::distance. Yes, it will be O(N) but nonetheless still
valid. If the implementation is to be extended to support these
categories of iterators (why not, BTW?), the iterator range base class
specializations will become equivalent and needless.

As for general application of this approach, I'd say it depends.
Clearly it costs some maintenance and compile times; the question is
what's the outcome of it and whether it encourages to write "good"
user side code. Depending on members of a third party component (in
case of member functions - on the particular signature thereof) is a
bad style, IMO, and should not be encouraged.


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