
Boost : 
Subject: Re: [boost] [guidelines] why template errors suck
From: Smith, Jacob N (jacob.n.smith_at_[hidden])
Date: 20100927 13:16:07
> Original Message
> From: boostbounces_at_[hidden] [mailto:boost
> bounces_at_[hidden]] On Behalf Of David Abrahams
> Sent: Sunday, September 26, 2010 9:49 PM
> To: boost_at_[hidden]
> Subject: Re: [boost] [guidelines] why template errors suck
>
> At Sun, 26 Sep 2010 22:31:54 0400,
> Eric Niebler wrote:
> > On 9/26/2010 9:44 PM, David Abrahams wrote:
> > > On Sep 26, 2010, at 8:55 AM, Eric Niebler wrote:
> > >> On 9/25/2010 1:24 PM, David Abrahams wrote:
> > >>> On Sep 24, 2010, at 11:51 PM, Eric Niebler wrote:
> > >>>> On 9/24/2010 9:37 PM, David Abrahams wrote:
> > >>>>
> > >>>> Haha! No, not at all. Let's rephrase the problem a bit. If we
> still had
> > >>>> C++0x concepts, what would the concept SpiritParser look like,
> such that
> > >>>> we could define spirit::qi::rule::operator= such that it
> required its
> > >>>> RHS to satisfy the SpiritParser concept?
> > >>>
> > >>> That's easy to answer; just look at the operations that
> > >>> operator= et. al expect of such a type. Wouldn't SpiritParser
> > >>> just be some simple refinement of Callable?
> > >>
> > >> No. rule::operator= expects SpiritParser to be a stronglytyped
> tree.
> > >
> > > Meaning? Spell it out and you have your requirements.
> >
> > Meaning:
> >
> > + If the topmost node has tagtype "plus", there must be exactly one
> > child node that models SpiritParser
> > + If the topmost node has tagtype "shift_right", there must be
> exactly
> > two child nodes that model SpiritParser,
> > + If the topmost node has tagtype "subscript", there must be a left
> > node that models SpiritParser and a right node that models
> PhoenixLambda,
> > ...
> > etc, etc, etc, ad nauseum
>
> No offense, but did you really answer the question I asked? Does
> operator= actually use those requirements? On the face of it, it just
> seems a lot more likely that it simply requires its RHS to also be a
> SpiritParser.
>
> > How do I express that as a concept?
>
> Summoning up my dim memory of proposed concept notation (so there are
> guaranteed nits to pick), that might translate into something like:
>
> concept SpiritNode<typename Node, typename Tag>
> {
> }
>
> template <class Node>
> concept_map SpiritNode<typename Node, plus>
> {
> requires SameType<Node::children,int_<1> >;
> typename child_t;
> requires SpiritParser<child_t>;
> child_t child;
> }
>
> template <class Node>
> concept_map SpiritNode<typename Node, shift_right>
> {
> requires SameType<Node::children,int_<2> >;
> typename child1_t;
> requires SpiritParser<child1_t>;
> typename child2_t;
> requires SpiritParser<child2_t>;
>
> child1_t child1;
> child2_t child2;
> }
>
> template <class Node>
> concept_map SpiritNode<typename Node, subscript>
> {
> requires SameType<Node::children,int_<2> >;
> typename child1_t;
> requires SpiritParser<child1_t>;
> typename child2_t;
> requires PhoenixLambda<child2_t>;
>
> child1_t child1;
> child2_t child2;
> }
>
> concept RHSOfAssign<typename X>
> {
> typename tag_type; // Every RHSOfAssign has an associated tag_type
> requires SpiritNode<X, tag_type>;
> }
>
> This isn't really how concepts were "meant to be used," though.
Disclaimer: it has been a couple of years since I worked with concepts.
concept ProtoNode<typename Node>
{
ChildList children = Node::children;
}
// Assert the pseudoprotounary_plus models a ProtoNode
template <ProtoNode Node> concept_map ProtoNode< unary_plus<Node> > { }
// Assert the pseudoprotobinary_plus models a ProtoNode
template <ProtoNode LNode, ProtoNode RNode> concept_map ProtoNode< binary_plus<LNode, RNode> > { }
// Assert the pseudoprotobinary_minus models a ProtoNode
template <ProtoNode LNode, ProtoNode RNode> concept_map ProtoNode< binary_minus<LNode, RNode> > { }
struct foo { };
struct bar { };
struct baz { };
concept_map ProtoNode<foo> { typedef nil children; }
concept_map ProtoNode<bar> { typedef nil children; }
auto rule = foo() + (+ bar()) + baz();
// error: baz does not satisfy the concept "ProtoNode".
// Pseudospirit concept.
concept SpiritNode<typename Node>
{
ChildList children = Node::children;
ForwardIterator iterator = Node::iterator;
iterator parse (iterator, iterator, Node&);
}
// Assert that all SpiritNodes model ProtoNodes
template <SpiritNode Node> concept_map ProtoNode<Node> { }
concept ShortProtoTree<typename Node>
{
// Checks that we have (in "handwavey" english):
// ProtoNode node that contains two ProtoNode nodes of ProtoNode.
// My personal ConceptGCC build uses "," not "&&".
requires ProtoNode<Node>,
ProtoNode<get_child<_0, ProtoNode<Node>::children>::type>,
ProtoNode<get_child<_1, ProtoNode<Node>::children>::type>;
}
concept IsBinaryPlusOperator<typename Node> { requires SpiritNode<Node>; }
concept IsUnaryPlusOperator<typename Node> { requires SpiritNode<Node>; }
concept SpiritPlusesShortProtoTree<typename Node>
{
// Checks that the "ShortProtoTree" is the expression: (+X) + (+Y)
requires SpiritNode<Node>,
ShortProtoTree<Node>,
IsBinaryPlusOperator<Node>,
IsUnaryPlusOperator<get_child<_0, ProtoNode<Node>::children>::type>,
IsUnaryPlusOperator<get_child<_1, ProtoNode<Node>::children>::type>;
}
I am waving my hands at the "get_child" functor; it is straightforward to describe using concepts.
Concepts are fairly tightly related to algebra declarations. Any algebra can be thought of as a tree, therefore, any tree should be checkable via concepts. Disjoint ("or") concept requirements are not needed in this situation since the concept mechanism will choose the most specialized concept that the model satisfies, not the least specialized. [This is not to say that disjoint concepts aren't necessary in some cases.]
j.
> 
> Dave Abrahams
> BoostPro Computing
> http://www.boostpro.com
>
> _______________________________________________
> Unsubscribe & other changes:
> http://lists.boost.org/mailman/listinfo.cgi/boost
Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk