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<vector<_self>()> >
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<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.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<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
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.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<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
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<is_placeholder<T>, 34 mpl::identity<void>, 35 get_neighborhood_type_impl<T> 36 >::type type; 37 }; and 47 template<class T> 48 struct get_iterator_type { 49 typedef typename mpl::eval_if<is_placeholder<T>, 50 mpl::identity<void>, 51 get_iterator_type_impl<T> 52 >::type type; 53 }; which are pretty much the same as what you sent me, but with the names changed. Are there any likely causes of these errors that occur to you, so I can try so fix them in a somewhat intelligent fashion? Thanks. -sc On Tue, Mar 11, 2014 at 6:57 PM, Steven Watanabe <watanabesj@gmail.com>wrote:
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 <boost/mpl/eval_if.hpp> #include <boost/mpl/identity.hpp> #include <boost/type_erasure/is_placeholder.hpp> Qualify the names boost::mpl::eval_if, boost::mpl::identity, and boost::type_erasure::is_placeholder if necessary.
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<is_placeholder<T>, 34 mpl::identity<void>, 35 get_neighborhood_type_impl<T> 36 >::type type; 37 };
<snip>
In Christ, Steven Watanabe
participants (2)
-
Samuel Christie
-
Steven Watanabe