$include_dir="/home/hyper-archives/boost/include"; include("$include_dir/msg-header.inc") ?>
Subject: Re: [boost] [guidelines] why template errors suck
From: David Abrahams (dave_at_[hidden])
Date: 2010-10-31 22:48:01
At Wed, 13 Oct 2010 10:09:39 -0700,
Steven Watanabe wrote:
> 
>  AMDG
> 
> Sorry for the delayed response.
Back atcha!  Been looking forward to getting back to this thread.
> >> As an example, let's use the fusion::less algorithm.
> 
> I was actually using a simplified version that requires
> both sequences to be the same type.  (And thus the
> same length).  A full lexicographical comparison is
> fine though.
> 
> > Close.  What you need is a refined concept for NonEmptyFusionSequence
> > that includes front_type and pop_front.  Just riffing here, but this
> > could work:
> >
> > concept FusionSequence<class S>
> > {
> >       CompileTimeInt size_type = int_<0>;
> >
> >       constexpr bool empty(const S&) { return size_type::value; }
> >       constexpr std::size_t size(const S&) { return size_type::value; }
> > }
> >
> > auto concept NonEmptyFusionSequence<class S>
> >    : FusionSequence<S>
> > {
> >       FusionSequence next_type;
> >       next_type pop_front(const S&);
> >
> >       typename front_type;
> >       front_type front(const S&);
> >
> >       CompileTimeInt size_type = int_<next_type::size_t::value+1>;
> > };
> >
> > // A shorter way. Because of refinement, this one will only get
> > // used when either S1 or S2 is empty.
> >
> > template<FusionSequence S1, FusionSequence S2>
> >    // a constraint you could add for clarity, but don't need
> >    // requires SameType<int_<0>, int_<S1::size_type()*S2::size_type()>  >
> > concept_map LessThanComparable<S1,S2>
> > {
> >      constexpr operator<(S1 const&, S2 const&)
> >      { return S1::size_type()<  S2::size_type(); }
> > }
> 
> Isn't the extra constraint needed to make sure
> that trying to compare sequences whose elements
> are /not/ LessThanComparable won't silently misbehave?
I see what you mean; I overlooked that issue.  Technically the correct
answer is that I guess it depends on your desired semantics; as I
coded it, it would mean
  make_tuple(1, 2) < make_tuple("a", "b", "c")
is that misbehavior?  Well, I guess it's not what tuple is currently
specified to do, so maybe it is.
> > template<NonEmptyFusionSequence S1, NonEmptyFusionSequence S2>
> >    requires LessThanComparable<S1::front_type,S2::front_type>
> >          &&  LessThanComparable<S1::next_type,S2::next_type>
> > concept_map LessThanComparable<S1,S2>
> > {
> >      operator<(S1 const&  x, S2 const&  y)
> >       { return front(x)<  front(y) || pop_front(x)<  pop_front(y) }
> > }
> 
> Okay.  Here's why I don't like this.
> 
> Suppose that I define a second algorithm with
> exactly the same requirements.  
So the first algorithm is fusion::less.  If you accept the above
concept_maps, fusion::less would just look like:
     template <FusionSequence S1, FusionSequence S2>
       requires LessThanComparable<S1,S2>
     bool less(S1 const& x, S2 const& y)
     {
         return x < y;
     }
> As an example,
> I'll use what fusion::less actually does.  (It doesn't
> quite do a lexicographical comparison.  It truncates
> to the length of the shorter sequence.)  This may
> be slightly contrived, but I'm sure you'll agree that
> there exist algorithms with identical requirements,
> neither one of which can be easily implemented
> in terms of the other.
Granted.
Okay, so that would be
     template <FusionSequence S1, FusionSequence S2>
       requires LessThanComparable<S1,S2>
     bool what_fusion_less_actually_does(S1 const& x, S2 const& y)
     {
         ...
     }
Right?  Same requirements.
> Now, suppose that I want to write a function
> template<FusionSequence S1, FusionSequence S2>
> void foo(S1, S2);
> which calls both of these algorithms.  How can I
> write the requirements for foo?
     template <FusionSequence S1, FusionSequence S2>
       requires LessThanComparable<S1,S2>
     bool foo(S1 const& x, S2 const& y)
     {
         return less(x,y) && what_fusion_less_actually_does(x,y);
     }
> a) requires LessThanComparable<S1, S2> &&
> TruncatingLessThanComparable<S1, S2>
>     Is every function template that calls foo also going to
>     have to list both of these?  This is silly and makes foo
>     difficult to change, because the concept requirements
>     include extraneous information.  Remember that the
>     two sets of types that model these concepts are the same.
> b) Leave it with just FusionSequence.
>     I hope this won't compile unless you have a concept_map
>     LessThanComparable<FusionSequence, FusionSequence>
>     which is a bad idea, as I explained above.
> c) Somehow define a concept that allows both LessThanComparable
>     and TruncatingLessThanComparable to be deduced.  This
>     would be ideal, but I don't have the least idea how to accomplish it.
> d) Something else I haven't thought of?
I don't understand why you'd go down any of those roads.  Am I missing
something?
-- Dave Abrahams BoostPro Computing http://www.boostpro.com