
On Mon, Oct 8, 2012 at 5:57 AM, Andrzej Krzemienski <akrzemi1@gmail.com> wrote:
Lots of reasons, but mostly it clearly delineates what is required from what is returned.
I agree with you that requires is important, particularly for concept-based overloads where one overload has more refined concepts than another
Can you guys give me an example of this?
std::advance, even in the C++98 standard library, is overloaded differently for input iterators than it is from bidirectional and random access iterators. With random access iterators, advance operates in constant time. With input iterators, advance operates linearly.
Sure, I understand:
template< class I, class Distance > requries InputIterator<I> void advance( I& it, Distance n ) { /* linear complexity... */ }
template< class I, class Distance > requries BidirectionalIterator<I> void advance( I& it, Distance n ) { /* ... */ }
template< class I, class Distance > requries RandomAccessIterator<I> void advance( I& it, Distance n ) { /* constant complexity... */ }
I agree, this type of overloading is a reason for having requires, enable_if will not suffice. Is there any other reason?
One (perhaps minor) reason is that enable_if is an ugly workaround rather than a decent solution for the problem. enable_if is a class template. WHen using it in declaring your function template you have to choose how you want to "uglify" your declaration: (1) Uglify the return type? (2) Add a useless function argument? (3) Add a useless template parameter?
"requires" on the other hand gives you another section in the declaration that does not interfere with function arguments or return value. This is only a problem of enable_if. If we have "mini-concepts" in form of static-if, the argument above would not hold anymore.
This is a problem of enable_if so I don't consider it a rationale for requires. As I briefly mentioned before, if the ugly enable_if is a concern in either forms: template< typename T, BOOST_ENABLE_IF(EqualityComparable<T>)> bool equal ( T const& a, T const& b ); template< typename T > typename std::enable_if<EqualityComparable<T>, bool>::type equal ( T const& a, T const& b ); Then I'll just provide a syntax similar to what is proposed by N3329: BOOST_CONTRACT_FUNCTION( template( typename T ) bool (equal) ( (T const&) a, (T const&) b ) if(EqualityComparable<T>) ) ; And same thing for class templates. Of course, if I end-up providing requires for the reason(s) 1) (and maybe 2)) below then you can use requires instead of enable_if and there's no point for me to also provide this N3329 "if" syntax. 1) Supporting concept based overloading/specializations is a valid argument for having requires as it cannot be done with enable_if (as Matt pointed out): template< class I, class Distance > requries InputIterator<I> void advance( I& it, Distance n ) { /* linear complexity... */ } template< class I, class Distance > requries BidirectionalIterator<I> void advance( I& it, Distance n ) { /* ... */ } template< class I, class Distance > requries RandomAccessIterator<I> void advance( I& it, Distance n ) { /* constant complexity... */ } 2) Another valid argument for requires is that the compiler will give the algorithm implementer an error if he/she uses the type in a way that doesn't model the concept (as Matt pointed out): template< typename T > requires EqualityComparable<T> bool equal ( T const& a, Tconst& b) { T x = a; // compiler error: T is not CopyConstructible, it's just EqualityComparable ... } Unfortunately, I don't think I can do this in a lib :( Can I? Does Boost.Generic provide such errors? Finally: is there any argument other than 1) and 2) for having requires? Thanks! --Lorenzo