
This may be a little OT but as it applies to metaprogramming and ideas from the book I thought it the best place to ask. On pgs 191/2 of the MPL book (section 9.5) is a set of ideas meant to introduce the inherit_linearly metafunction. There are some things I want to do that suggested this was actually the better way to go for me. So I implemented something like the following: struct empty {}; template < typename FIELD, typename CDR > struct rec : CDR { typename FIELD::type value; rec() : value() {} }; template < typename VEC > struct generate_record //: boost::mpl::inherit_linearly< VEC, boost::mpl::inherit< rec<pl::_2>, pl::_1> >::type : boost::mpl::fold< VEC, empty, rec< pl::_2, pl::_1> > {}; I implemented a getter function like so: template < typename FIELD, typename CDR > typename FIELD::type & get(rec< FIELD, CDR > & r) { return r.value; } Now, minus the "field" concept this seems to be exactly the same basic thing. The field concept is something I need for what I'm working on that currently, for this test, just has a type in it. I create a "record" like so: typedef generate_record< boost::mpl::vector<field1, field2, field3>
::type test_record;
When I print the type I end up with: "rec<field3,rec<field2,rec<field1,empty> > >" and in main attempt to access it: test_record tr; get<field1>(tr) = 3; This works fine in comeau and I'd expect it to work anywhere but MSVC++ 8 doesn't like it. It says that the FIELD param is ambiguous and could be field1 (what I specified in the call) or field3 (the first field on the inheritance tree). The error text is exactly: 1>e:\dev_workspace\experimental\record_generation\record_generation\main.cpp(78) : error C2782: 'FIELD::type &get(rec<FIELD,CDR> &)' : template parameter 'FIELD' is ambiguous 1> e:\dev_workspace\experimental\record_generation\record_generation\main.cpp(58) : see declaration of 'get' 1> could be 'field3' 1> or 'field1' I'm calling this a compiler bug at this point. I suspect many here have had to deal with this, since it's basic template usage, and might know a workaround. Or maybe you see something I've done incorrectly.

Noah Roberts wrote:
This may be a little OT but as it applies to metaprogramming and ideas from the book I thought it the best place to ask.
On pgs 191/2 of the MPL book (section 9.5) is a set of ideas meant to introduce the inherit_linearly metafunction. There are some things I want to do that suggested this was actually the better way to go for me.
I solved the issues I had with the other way to do it, using mpl::inherit_linearly, so this isn't such a problem anymore. It's obviously a compiler bug, one they actually fixed in the next version.

Noah, please see my answer below: On Tue, Mar 3, 2009 at 5:59 PM, Noah Roberts <roberts.noah@gmail.com> wrote:
template < typename FIELD, typename CDR > typename FIELD::type & get(rec< FIELD, CDR > & r) { return r.value; }
You should use the static_cast<SomeFieldSpecificType>(r) here to fix the problem. The only problem is, that 'r' is the entire recordset, and you can't cast it to itself, nor you can extract the SomeFieldSpecificType. Your example work with MSVC 9. I have rewritten it to use the static_cast, but did not test it with MSVC 8. Give it a try, I think this should work: #include <boost/mpl/fold.hpp> #include <boost/mpl/vector.hpp> #include <boost/mpl/inherit.hpp> #include <boost/mpl/identity.hpp> #include <boost/mpl/placeholders.hpp> #include <boost/mpl/inherit_linearly.hpp> namespace pl = boost::mpl::placeholders; namespace mpl = boost::mpl; struct empty {}; template <typename FIELD> struct rec { typename FIELD::type value; rec() : value() {} }; template < typename VEC > struct generate_record : boost::mpl::inherit_linearly< VEC, mpl::inherit< rec<pl::_2>, pl::_1>
::type {};
template < typename FIELD, class Records> typename FIELD::type & get(Records& rs) { return static_cast<rec<FIELD>&>(rs).value; } typedef mpl::identity<int> field1; typedef mpl::identity<double> field2; typedef mpl::identity<char> field3; typedef mpl::identity<int> field4; typedef generate_record<mpl::vector< field1, field2, field3> >::type test_record; int main() { test_record tr; get<field1>(tr) = 3; get<field2>(tr) = 3.0; get<field3>(tr) = 'a'; get<field4>(tr) = 10; //this won't work as intended return 0; } This might be interesting to Dave: If same types are passed into the inheritance, no compiler error is issued since the types are probably managed by mpl::set(???). Compiler will silently compile but get<field4>(tr) = 10 will overwrite the value of get<field1>(tr), which is probably not intended. And we intend in MPL to produce as mucht errors as possible, since the compiler is our tester ;) I would expect, that at least here an error is produced, that I am trying to derive from the same type twice. This is a philosofical discussion, since I can modify inherit to inherit virtually and this might be fine than, but throwing away the type from the inheritance is not ok. At least MSVC produced the following type: boost::mpl::inherit2<rec<boost::mpl::identity<char>
,boost::mpl::inherit2<rec<boost::mpl::identity<double> ,rec<boost::mpl::identity<int> > > >
With Kind Regards, Ovanes

On Tue, Mar 3, 2009 at 11:27 PM, Ovanes Markarian <om_boost@keywallet.com>wrote:
Noah,
please see my answer below:
On Tue, Mar 3, 2009 at 5:59 PM, Noah Roberts <roberts.noah@gmail.com>wrote:
template < typename FIELD, typename CDR > typename FIELD::type & get(rec< FIELD, CDR > & r) { return r.value; }
You should use the static_cast<SomeFieldSpecificType>(r) here to fix the problem. The only problem is, that 'r' is the entire recordset, and you can't cast it to itself, nor you can extract the SomeFieldSpecificType.
Your example work with MSVC 9. I have rewritten it to use the static_cast, but did not test it with MSVC 8. Give it a try, I think this should work:
#include <boost/mpl/fold.hpp> #include <boost/mpl/vector.hpp> #include <boost/mpl/inherit.hpp> #include <boost/mpl/identity.hpp> #include <boost/mpl/placeholders.hpp> #include <boost/mpl/inherit_linearly.hpp>
namespace pl = boost::mpl::placeholders; namespace mpl = boost::mpl;
struct empty {};
template <typename FIELD> struct rec { typename FIELD::type value;
rec() : value() {} };
template < typename VEC > struct generate_record : boost::mpl::inherit_linearly< VEC, mpl::inherit< rec<pl::_2>, pl::_1>
::type {};
template < typename FIELD, class Records> typename FIELD::type & get(Records& rs) { return static_cast<rec<FIELD>&>(rs).value; }
typedef mpl::identity<int> field1; typedef mpl::identity<double> field2; typedef mpl::identity<char> field3; typedef mpl::identity<int> field4;
typedef generate_record<mpl::vector< field1, field2, field3> >::type test_record;
int main() { test_record tr; get<field1>(tr) = 3; get<field2>(tr) = 3.0; get<field3>(tr) = 'a'; get<field4>(tr) = 10; //this won't work as intended
return 0; }
This might be interesting to Dave: If same types are passed into the inheritance, no compiler error is issued since the types are probably managed by mpl::set(???). Compiler will silently compile but get<field4>(tr) = 10 will overwrite the value of get<field1>(tr), which is probably not intended. And we intend in MPL to produce as mucht errors as possible, since the compiler is our tester ;)
I would expect, that at least here an error is produced, that I am trying to derive from the same type twice. This is a philosofical discussion, since I can modify inherit to inherit virtually and this might be fine than, but throwing away the type from the inheritance is not ok. At least MSVC produced the following type:
boost::mpl::inherit2<rec<boost::mpl::identity<char>
,boost::mpl::inherit2<rec<boost::mpl::identity<double> ,rec<boost::mpl::identity<int> > > >
Sorry for the last misleading paragraph. I forgot to put the field4 into the typesequence. After putting it in I received expected compiler error. MPL Rocks! Best Regards, Ovanes

Ovanes Markarian wrote:
Noah,
please see my answer below:
On Tue, Mar 3, 2009 at 5:59 PM, Noah Roberts <roberts.noah@gmail.com <mailto:roberts.noah@gmail.com>> wrote:
template < typename FIELD, typename CDR > typename FIELD::type & get(rec< FIELD, CDR > & r) { return r.value; }
You should use the static_cast<SomeFieldSpecificType>(r) here to fix the problem. The only problem is, that 'r' is the entire recordset, and you can't cast it to itself, nor you can extract the SomeFieldSpecificType.
Not really. The get function is called with an explicit template argument for the first argument: get<field1>(r); The resolution should therefore cast the rec to the correct base class so that r.value actually is the appropriate call. Putting a static cast in the function body would actually have no effect and wouldn't resolve the ambiguity the compiler seems to think exists. The type passed into the function is a rec<field3, XXX> but the explicit notation would require the function to expect a rec<field1,XXX>; the compiler is saying it can't decide between them. I don't know where in the standard this would be specified but I expect it says to obey the explicit resolution over implicit.
Your example work with MSVC 9.
Yeah, I think they fixed the bug. I tried it with express edition and it functions. Comeau also eats it without error. I have rewritten it to use the
static_cast, but did not test it with MSVC 8. Give it a try, I think this should work:
This solution is what the instruction comes to in the book but isn't along the lines of my question. For one thing I wanted the rec<> template to inherit directly from the other field recs, which my version (and the first example in the book) does. Your code doesn't. I am going to end up using something more like this version now, since I found what I was doing wrong earlier, but it still doesn't address the original problem that I'm pretty confident is a bug in the compiler. My question was regarding the former technique since I thought I couldn't use the latter. Anyway, thanks for the help. I think I'm onto a solution to my original problem if not a workaround for making the compiler swallow the book's sample code.
participants (2)
-
Noah Roberts
-
Ovanes Markarian