
On 4/27/2011 1:06 PM, Larry Evans wrote:
Use of mine is more like so:
struct field0 { typedef int value_type; }; struct field1...2 ...
struct my_reflected_type : build_class < var< field0, rw> , var< field1, r> // can't assign through reflection.
Why not:
var< field> , var< field const>
instead? I guess I'd have to see the code to really understand why the extra type parameter is needed, but maybe a short explanation would be enough.
I suppose that'd be an interesting method of doing it. The field itself though isn't the type stored so the const would have to be applied to that value or applied in the same way I end up using the access rights. Currently though in a reflected type containing a read-only field the value itself isn't actually read only. It may be that the class itself may implement other behavior that changes the value. It just means that the value is read only through the reflection API. Thus when I say "get<field>(object)" I get a const reference if the field is non-writable or object is const. If, on the other hand, I violate the API through casting (which is more normal from inside the class) I can write to that value from a non-const member.
>::type { virtual ~my_reflected_type(){} DECLARE_PARAM_CONSTRUCTOR(my_reflected_type);
Could you provide the source code for:
DECLARE_PARAM_CONSTRUCTOR
to give us some idea of what it's doing?
template < typename Params > name (Params const& params) : type(params) {} It just saves time. The type you inherit from (which declares itself as type inside itself like a lot of meta-objects) has two constructors. One is the default, the other is just like the above and forwards the params to the value implementation objects to either accept or discard. A lot of times you won't care to make one of these yourself, but instead make a constructor that uses params to initialize. It's currently important for base classes though so derived classes can forward params. Doing correct base construction is one of the to-be-solved things.
};
struct my_reflected_type2 : derive_from < my_reflected_type , var< field2, rw> >::type { my_reflected_type2() : type(( field0()<= some_val , field1()<= some_val , field2()<= some_val )) { // directly access read-only value and assign... var<field1,r>::value = 66.; } };
Hmm... does the user have to repeat this some number of times, same the number of fields in the my_reflected_type? IOW, for I=3...N (where N is number of fields in my_reflected_type):
my_reflected_typeI { //repeat like my_reflected_type2 };
Or is this done by the macro using boost,preprocessor library? I would guess the latter because providing all this boilerplate code would seem too much to me.
You can initialize or not initialize any field you chose, thus named params rather than construction like tuple<> or others. If you initialize with a set of params, the values they target will be thus initialized while those you don't supply will be default constructed. (so yeah, sort of has to do with my earlier question) If your value can't be default constructed you HAVE to provide a param for it. It then has to be copy constructable for the param will first initialize the value from your provided data. The type that feeds into a set of params is specifically the value of the field in other words (though I'm sure this could be changed, thinking of it now). If your value is default constructible it need not be copy constructible. If it is not, it'll have to be initialized to some reasonable value outside the API and you won't be able to assign to it through reflection. The current state doesn't do functions though I have ideas there. We're currently calling them "records".
I also have a ref<> so bases can have fields to abstract types.
So far functions haven't been needed here so there's none but I think I have a handle on how that could be done.
All of the above can be treated as a fusion sequence and/or fusion associative sequence (including the param list).
Building records on the fly with field()<=value syntax was very desired. Comes in handy when you have a function expecting a record with x,y,z fields in it, have those values, but don't want to build the record class.
I don't understand that. Could you be more concrete in describing this use case, maybe by providing a concrete example?
So for instance: template < typename Record > void fun(Record const& rec) { static_assert(has_field<Record, what_i_need>::value, "Supplied record doesn't have the necessary data!"); ..... } I can call this function like so: what_i_need::value_type value; int something_else; fun(( what_i_need() <= value , int_field() <= something_else)); Records and param lists being nearly interchangeable in this regard. Only showing the int_field() because it can happen...the function simply ignores what it doesn't know about.
---------------------------- BTW, a previous post of your's to the users list:
http://thread.gmane.org/gmane.comp.lib.boost.user/66818/focus=67038
seems related to your:
field()<=value
syntax. Is it?
Sort of. It's more about initializing the values themselves with the params. I ended up with something more like: template < typename Params > value_impl(Params & p, typename boost::enable_if< has_field<Params,my_field> >::type * = 0) : value(get<my_field>(p)) {} template < typename Params > value_impl(Params & p, typename boost::disable_if< has_field<Params,my_field> >::type * = 0) : value() {} I don't have rights to the code though I do the idea. If I did it I'd need to address a few things: * correct base initialization. With reflected types though your "base" is not your direct, actual base so that becomes an issue. * Better implementation of fields represented by abstract types. Currently there's three approaches: 1) have the field in the base and make it refer to the abstract type. 2) have the field in the derived and make it refer to the most derived type. Of course now you don't have access to it from the base. 3) Put one field in the base and a different field in the derived. Make the base's a "reference" field. Does the trick but it's hacky. I really want the best of both worlds. Put the field in the base to the abstract type. When I request the field from a derived record have it return the derived type. In other words: struct base_field_type; struct derived_field_type; struct field { typedef base_field_type value_type; }; derived d; base * b = &d; decltype(get<field>(d)) == derived_field_type& decltype(get<field>(*b)) == base_field_type& * functions. I imagine something like so: struct reflected : build_class < fun<fieldx, void(int)> >::type { void call(fieldx, int) { .... } }; reflected r; call<fieldx>(r, 42); // maybe call<fieldx>(r)(42); I'm not sure how much actual value this has though. Personally I don't have much use for it. On the other hand, I do have use for "fields" implemented by functions such that: int x = get<fieldx>(r); is actually a call to a function rather than reference to a variable in r.