Boost logo

Boost :

Subject: Re: [boost] [guidelines] why template errors suck
From: David Abrahams (dave_at_[hidden])
Date: 2010-09-27 13:02:25


On Sep 27, 2010, at 10:11 AM, Eric Niebler wrote:
>
> On 9/27/2010 12:49 AM, David Abrahams wrote:
>> 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 strongly-typed tree.
>>>>
>>>> Meaning? Spell it out and you have your requirements.
>>>
>>> Meaning:
>>>
>>> + If the topmost node has tag-type "plus", there must be exactly one
>>> child node that models SpiritParser
>>> + If the topmost node has tag-type "shift_right", there must be exactly
>>> two child nodes that model SpiritParser,
>>> + If the topmost node has tag-type "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?
>
> It does. operator= doesn't know how to process the tree (that is, what
> the requirements are) until it looks at the top-most node type and
> dispatches to the correct helper functions. Those functions have their
> own requirements determined solely by the substructure of the trees they
> operate on.
>
> For instance, take semantic actions, denoted by the subscript tag. If a
> subscript node appears anywhere in the tree, the right child of that
> node must satisfy the concept PolymorphicFunctionObject. rule::operator=
> will fail to compile if it does not; it has assumed that requirement as
> a result of the recursive function calls made within the body of
> operator=. I'd like to be able to check for that condition up front. I
> still don't know how using concepts.
>
>> On the face of it, it just
>> seems a lot more likely that it simply requires its RHS to also be a
>> SpiritParser.
>
> Where a SpiritParser is ...?
>
>>> 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.
>
> You haven't shown how the SpiritNode and SpiritParser concepts are
> related.

Of course not; you didn't say they were related. I just translated the constraints you wrote down into concepts-land.

> There must be some recursive relationship, like "a SpiritParser
> is a SpiritNode<plus> /or/ a SpiritNode<right_shift> /or/ ..." It
> requires OR constraints

Do say that, you just use concept_maps to declare that SpiritNode<plus> models SpiritParser, etc.:

  concept_map SpiritParser<SpiritNode<plus> >
  {
      // ...
  }

  concept_map SpiritParser<SpiritNode<right_shift> >
  {
      // ...
  }

> which, as Sebastian has pointed out, were yanked
> from the concepts proposal.

With good reason.

> rule::operator= is an algorithm. The structure of the type on which it's
> parametrized and the grammar to which that type must conform together
> determine what the overall algorithm requirements are. It by necessity
> cannot be expressed without OR constraints.

I don't understand how you can come to that conclusion with such certainty, while at the same time declaring that you don't understand concepts.

> What I seem to have is a
> situation where an algorithm has type requirements that cannot be
> expressed with concepts, so concepts cannot help me validate my type
> parameter.

I don't see it (yet), sorry. Am I missing something?

--
Dave Abrahams
BoostPro Computing
http://boostpro.com

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