Indirectly 'recursive' type erasure
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
test;
class Test { public: vector<test> collection(); }; 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. What do I need to do in order to be able to return types that are dependent on the erasure type? 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. Any assistance would be most helpful. Thanks, -sc
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
()> > test;
class Test { public: vector<test> collection(); };
Try this:
struct my_requirements;
typedef any
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.h... "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
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
requirements;
typedef any<requirements> test;
typedef any
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
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
()> > test;
class Test { public: vector<test> collection(); };
Try this:
struct my_requirements; typedef any
test; struct my_requirements mpl::vector<..., has_collection > {}; 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.h...
"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
()> 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
> _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
erased_collection; typedef any 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
AMDG On 03/11/2014 01:42 PM, Samuel Christie wrote:
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.
You can either use a nested typedef (like T::iterator) or you can use decltype(boost::declval<T>().collection()).
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.
That shouldn't have been a problem, since equality_comparable defines both == and !=.
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.
You're really close. I've gotten your example working. See attached. (I also cleaned it up a bit by using BOOST_TYPE_ERASURE_MEMBER/FREE). Tested with MSVC 12 and GCC 4.7. In Christ, Steven Watanabe
Thanks again for your help. I was also able to get that example to compile,
which was perfect. Unfortunately, it seems rather fragile. I had copied
most of the pieces over into a split test.hpp/test.cpp, and kept getting
errors. I did eventually resolve the problem by more completely replacing
them with your code directly, but I wasn't able to figure out what was
causing the problem. Of course, that means when I tried to apply it to my
real code, I ended up with the same error:
solution.hpp:36:3: error: template argument 1 is invalid
solution.hpp:36:4: error: expected identifier before '::' token
solution.hpp:36:6: error: typedef name may not be a nested-name-specifier
solution.hpp:36:6: error: expected ';' at end of member declaration
solution.hpp:36:11: error: 'type' does not name a type
solution.hpp:52:3: error: template argument 1 is invalid
solution.hpp:52:4: error: expected identifier before '::' token
solution.hpp:52:6: error: typedef name may not be a nested-name-specifier
solution.hpp:52:6: error: expected ';' at end of member declaration
solution.hpp:52:11: error: 'type' does not name a type
the relevant pieces of code were the following:
31 template<class T>
32 struct get_neighborhood_type {
33 typedef typename mpl::eval_if
AMDG
On 03/11/2014 01:42 PM, Samuel Christie wrote:
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.
You can either use a nested typedef (like T::iterator) or you can use decltype(boost::declval<T>().collection()).
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.
That shouldn't have been a problem, since equality_comparable defines both == and !=.
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.
You're really close. I've gotten your example working. See attached. (I also cleaned it up a bit by using BOOST_TYPE_ERASURE_MEMBER/FREE). Tested with MSVC 12 and GCC 4.7.
In Christ, Steven Watanabe
_______________________________________________ Boost-users mailing list Boost-users@lists.boost.org http://lists.boost.org/mailman/listinfo.cgi/boost-users
AMDG On 03/13/2014 01:09 PM, Samuel Christie wrote:
Thanks again for your help. I was also able to get that example to compile, which was perfect. Unfortunately, it seems rather fragile. I had copied most of the pieces over into a split test.hpp/test.cpp, and kept getting errors. I did eventually resolve the problem by more completely replacing them with your code directly, but I wasn't able to figure out what was causing the problem. Of course, that means when I tried to apply it to my real code, I ended up with the same error:
Make sure that everything is in scope:
#include
solution.hpp:36:3: error: template argument 1 is invalid solution.hpp:36:4: error: expected identifier before '::' token solution.hpp:36:6: error: typedef name may not be a nested-name-specifier solution.hpp:36:6: error: expected ';' at end of member declaration solution.hpp:36:11: error: 'type' does not name a type solution.hpp:52:3: error: template argument 1 is invalid solution.hpp:52:4: error: expected identifier before '::' token solution.hpp:52:6: error: typedef name may not be a nested-name-specifier solution.hpp:52:6: error: expected ';' at end of member declaration solution.hpp:52:11: error: 'type' does not name a type
the relevant pieces of code were the following:
31 template<class T> 32 struct get_neighborhood_type { 33 typedef typename mpl::eval_if
::type type; 37 }; <snip>
In Christ, Steven Watanabe
participants (2)
-
Samuel Christie
-
Steven Watanabe