Boost logo

Boost Users :

Subject: Re: [Boost-users] 'Hashable' concept for type erasure
From: Samuel Christie (schrist_at_[hidden])
Date: 2014-03-25 13:04:46


Maybe we could do something like your previous example that did some
conversion and checking in the concept interface? I really only need to
know whether or not it was already in the collection. I don't actually need
the iterator for the matching item.

Type erasure is definitely harder to set up than I initially presumed, and
you have my admiration for being capable of writing the library. Debugging
it seems particularly challenging.
On Mar 24, 2014 4:12 PM, "Steven Watanabe" <watanabesj_at_[hidden]> wrote:

> AMDG
>
> On 03/24/2014 11:46 AM, Samuel Christie wrote:
> > Interesting. That looks useful, but at the same time I think I can
> actually
> > get away without erasing _value. The actual type would be the erased type
> > we were working on earlier, so I should be able to just stick it in
> > explicitly.
> >
> > How would you erase insert() though? Its return type seems fairly
> > complicated. I tried using std::pair<te::any<te::forward_iterator<> >,
> > bool>, but I get "invalid initialization of reference of type 'int&' from
> > expression of type 'const int'" for the simple test case.
> >
>
> This is probably because unordered_set doesn't
> provide mutable iterators. You'll need to
> set the reference type of the iterator.
>
> Also if you create an independent any type
> for the iterator, you probably won't be able
> to do much with it, and you might as well
> return void. The iterator should really be
> another associated type, but that creates
> another problem.
>
> Handling composite return types like std::pair
> is painful. The library doesn't handle it
> because I don't have a good way to deal with
> it generically. The basic problem is that on
> the inside you have
> std::pair<std::unordered_set<int>::iterator, bool>
> and on the outside you have
> std::pair<any<requirements, _iter>, bool> and
> I need to convert from one to the other.
> Of course, it's fairly easy to do this for
> std::pair, but imagine instead trying to
> handle this for some arbitrary template
> with an unknown set of accessors and an
> unknown set of constructors. I'd need to
> have some kind of traits template that could
> be specialized to handle the conversion for
> specific types. If this were all, it would
> be manageable, but it gets worse.
>
> The library needs to convert from T (the
> stored type) to any<Concept, Placeholder>.
> The interface boundary inside the library
> doesn't know anything about T (this is the
> critical requirement for any kind of type
> erasure). It also doesn't know anything
> about Concept (This is necessary to allow
> composition of concept requirements). As a
> result the actual type passed through the
> dispatcher cannot be any<Concept, Placeholder>
> nor can it be T. It has to be void* (or
> something equivalent).
>
> So, given a template X<P>, which is used as the
> return type of an erased function, the actual
> conversions that we need are
> X<T> -> X<void*> -> X<any<C, P> >. This
> is now a problem, because there's absolutely
> no guarantee that X<void*> is a legal type.
> I don't have a good solution for this in
> the general case.
>
> It is possible to handle insert like this:
>
> typedef any<copy_constructible<> > internal_type;
> template<class C, class T, class I>
> struct has_insert {
> static std::pair<internal_type, bool> apply(C& c, const T& t)
> {
> // implicit conversion of std::pair should work,
> // but we need to make sure that we use the
> // specified iterator type regardless of what
> // c.insert actually returns.
> std::pair<I, bool> result = c.insert(t);
> return result;
> }
> };
>
> namespace boost { namespace type_erasure {
> template<class C, class T, class I, class Base>
> struct concept_interface<has_insert<C, T, I>, Base, C>
> : Base
> {
> std::pair<typename rebind_any<Base, I>::type, bool>
> insert(typename as_param<Base, const T&>::type arg)
> {
> std::pair<internal_type, bool> result =
> call(has_insert<C, T, I>(), *this, arg);
> // Force the iterator to the correct any type.
> // We know that this is safe because the
> // iterator comes from has_insert::apply
> // which guarantees that the iterator
> // is the correct type for the placeholder I.
> typename rebind_any<Base, I>::type iter(
> result.first, binding_of(*this));
> return std::make_pair(iter, result.second);
> };
> };
> }}
>
> Now you would just need to specify that I is a
> [forward|bidirectional|random_access]_iterator
> with a reference type of [const] T&. (Warning,
> this code is completely untested.)
>
> In Christ,
> Steven Watanabe
>
> _______________________________________________
> Boost-users mailing list
> Boost-users_at_[hidden]
> http://lists.boost.org/mailman/listinfo.cgi/boost-users
>



Boost-users list run by williamkempf at hotmail.com, kalb at libertysoft.com, bjorn.karlsson at readsoft.com, gregod at cs.rpi.edu, wekempf at cox.net