Boost logo

Boost :

Subject: Re: [boost] [type_erasure] Downcasting is now possible
From: Steven Watanabe (watanabesj_at_[hidden])
Date: 2015-03-09 21:21:15


On 03/09/2015 06:36 PM, Matt Calabrese wrote:
> On Mon, Mar 9, 2015 at 4:29 PM, Steven Watanabe <watanabesj_at_[hidden]>
> wrote:
>> 1) You don't pay for what you don't use. Putting
>> the registration in the constructor means that
>> it will always happen whether it's needed or not.
>> 2) It still won't catch everything. In the example
>> I posted, the object is captured by an any type
>> which does not support callable, and later cast
>> to another any type which does. The constructor
>> will therefore not instantiate callable<void()>.
>> I think that explicit manual registration is
>> less likely to to cause hard to find bugs that
>> automatic registration that only works most
>> of the time.
> Okay, this facility is much different from what I thought it was. I should
> have looked at the example code more closely before replying. I read the
> description and thought it was for the following type of situation:
> //////////
> void foo() {}
> function_any<void()> fun_foo = &foo; // Start by type-erasing via a
> callable concept
> // Convert to a less-refined concept
> plain_any any_foo = fun_foo; // target type is still void(*)(), no
> additional indirection
> // Get the object back as a function_any<void()>
> dynamic_any_cast<function_any<void()>>(any_foo); // should succeed
> //////////
> In other words, I assumed it only worked if the type were originally erased
> via the more-refined concept before being converted to the less-refined
> any. In this case I imagine you would be able to keep track of the
> information by way of the original conversion.

  From an implementation stand-point, just casting
to the original captured type is pretty easy to
support. The problem is that if I support that,
then several other kinds of casts should be possible
as well.

  If we have an any, we should be able to do
an upcast followed by a downcast, regardless
of where the any came from. Thus, the following
sequence should work:
   - capture as RandomAccessIterator
   - cast to BidirectionalIterator
   - cast to ForwardIterator
   - dynamic_any_cast back to BidirectionalIterator

  The cast sequence RandomAccessIterator -> BidirectionalIterator ->
ForwardIterator should be exactly equivalent to
RandomAccessIterator -> ForwardIterator. Therefore,
the following should also work:
   - capture as RandomAccessIterator
   - cast to ForwardIterator
   - dynamic_any_cast to BidirectionalIterator

  The simplest rule to make sure that such conversions
always work is to say that if an object was originally
captured as ConceptA, then a dynamic_any_cast from
ConceptB to ConceptC will work if ConceptA is more refined
than ConceptC.

  So far it's all pretty straightforward. Now we come to
the annoying part. I think that every any which holds the
same value should be equivalent. In other words, if I have
any<...> a1, a2; and typeid_of(a1) == typeid_of(a2), then
dynamic_any_cast<any<C> >(a1) should be successful iff
dynamic_any_cast<any<C> >(a2) is also successful. I
really don't want to make it possible for objects that
compare equal to behave differently.

  This in turn means that a cast may be successful regardless
of the original concept used to capture the object. At this
point, we've basically generalized dynamic_any_cast back to my
current implementation. The only real choice is whether to
auto-register in the constructor or not.

  I could be convinced that auto-registration is the way
to go, but unless you or someone else has a very compelling
argument, I'd rather use manual registration until there's
real usage data for this feature. It'll be much easier
to retrofit auto-registration into a system that uses
manual registration then it would be to remove automatic
registration after I already provide it.

In Christ,
Steven Watanabe

Boost list run by bdawes at, gregod at, cpdaniel at, john at