Ok, that looks very promising. I was able to get the simple example at the top to work, returning a vector of pre-erased test objects, but I had some more trouble with the later one. My current test structure looks like:

class Test;

class Collection {
  class iterator {
  public:
    explicit iterator(int i) : index(i) {};
    iterator& operator++();
    Test operator* () const;
    bool operator== (const iterator& other) const;
    int index;
  };
public:
  Collection(int i) :value(i) { };
  friend iterator begin(Collection& c);
  friend iterator end(Collection& c);
  int value;
};

class Test {
public:
  Collection collection();
};

I'm not sure how to do the get_collection_type deduction in such a way that it works for more than one type of collection. I.e., both a vector<T> and a Collection as defined above.

I also tried to do a test with the slightly more basic vector<Test> collection type. I got close, but I eventually had issues with the != required by the foreach loop pattern.

Here's a paste of most of the test code: pastebin.com/GiQwQTcq

Hopefully what I'm having trouble with makes sense to you; if not, maybe just providing a few more examples of the pieces required to make a for(auto i : t.collection()) work based on the above class declaration would be helpful. I feel like either I'm getting close, or I'm trying to do something I shouldn't be.


On Fri, Mar 7, 2014 at 11:39 AM, Steven Watanabe <watanabesj@gmail.com> wrote:
AMDG

On 03/06/2014 04:01 PM, Samuel Christie wrote:
> I'm trying to create a type erasure concept for a type that has a member
> function which can return a custom collection of itself.
>
> Having had little luck with the general formulation, I tried simplifying it
> to:
>
> BOOST_TYPE_ERASURE_MEMBER((has_collection), collection, 0);
>
> typedef any<
>   mpl::vector<
>     copy_constructible<>,
>     typeid_<>,
>     relaxed,
>     has_collection<vector<_self>()>
>     >
>   > test;
>
> class Test {
> public:
>   vector<test> collection();
> };
>

Try this:

struct my_requirements;
typedef any<my_requirements> test;
struct my_requirements
  mpl::vector<..., has_collection<vector<test>()> >
{};

The easiest way to handle a cyclic dependency
is to forward declare something, in this case
my_requirements, should do the trick.

> However, I get conversion errors if the Test::collection method returns
> either vector<Test> or vector<test>; it only seems to match if I have it
> literally return vector<_self>, which implies to me that I'm not
> understanding what I'm doing, and that _self isn't getting substituted in
> this case.
>

That is the expected behavior.  See
http://www.boost.org/doc/libs/1_55_0/doc/html/boost_typeerasure/conceptdef.html

"The template parameters of the concept may involve placeholders. The
following are considered.

    Each template argument may be a cv and/or reference qualified
placeholder type.
    If a template argument is a function type, its arguments and return
type may be cv/reference qualified placeholders.

Any other placeholders are ignored."

> What do I need to do in order to be able to return types that are dependent
> on the erasure type?

It's technically possible for me to make has_collection<vector<_self>()>
work, but it would require a rather messy customization layer.
It can't be made to work automatically for any X<T> without help.

> My actual code uses a more indirect relationship, with
> the collection method returning a custom erased collection type that has an
> erased iterator that can dereference to the equivalent of Test. However,
> since there is still a form of cyclic dependency, I'm not really sure what
> I can do about it. I've tried using a custom struct based concept that had
> direct template arguments in the place of 'boost type erasure member', but
> I think I understand that technique even less, and it didn't seem to help
> much.
>
> It looked like there might be something useful under the Associated Types
> section of the type erasure documentation, but I couldn't quite figure it
> out.
>

It sounds like Associated Types may be
what you want for your real use case.
It would look something like this:

// Calculates the return type of T::collection()
template<class T>
struct get_collection_type {
  typedef std::vector<T> type;
};

typedef deduced<get_collection_type<_self> > _collection;

typedef mpl::vector<
    // requirements on test
    copy_constructible<>,
    typeid_<>,
    has_collection<_collection()>,
    // requirements on _collection
    copy_constructible<_collection>,
    // has_begin/has_end<_collection>
    // requirements on the iterator (using _self as the value_type)
  > requirements;

typedef any<requirements> test;
typedef any<requirements, _collection> erased_collection;
typedef any<requirements, _iterator> erased_iterator;

Note that since test, the erased collection, and the
erased iterator have a cyclic dependency, the requirements
for them all need to be defined at once, for the library
to resolve it.

In Christ,
Steven Watanabe

_______________________________________________
Boost-users mailing list
Boost-users@lists.boost.org
http://lists.boost.org/mailman/listinfo.cgi/boost-users