
There are still things to be improved, but at least we have (almost) all the desired functionality. The missing features that I can see are: - handling multiple inheritance (both declaration of super classes and recursive retrieval of vtypes); - using exact() in typeof_ to fetch vtypes from the exact static type (needs mlc::any). I'll try to factor this code (some incriminated sections have been tagged as such). https://svn.lrde.epita.fr/svn/oln/trunk Index: ChangeLog from Roland Levillain <roland@lrde.epita.fr> Revamp the virtual types (aka properties) system. No longer use the C++'s inheritance mechanism to ``pack'' the internal vtypes of a class. Rely on a metacode algorithm to recursively look for vtypes in internal and external vtypes instead, using both the super link and a ``pseudosuper'' link to visit the upper classes. The set/get classes have been replaced by a single class (in fact, by two classes, one for internal vtypes, the other for external vtypes). The pseudosuper link is used to inherit (or fetch) the vtypes from a given class, without needing to inherit from this class. * metalic/mlc/properties.hh (mlc_equip_namespace_with_properties): Rewrite this macro. (set_types, set_ext_types): Rename as... (vtypes, ext_vtypes): ...this. (get_types, get_ext_type): Remove. * metalic/tests/properties.cc: Update the test. Check for new cases (external vtype, pseudo inheritance of vtypes). (rec_get_vtype, rec_get_ext_vtype): New. This class holds the algorithm for the recursive retrieval of internal/external vtypes. (typeof_): Adjust. mlc/properties.hh | 281 +++++++++++++++++++++++++++++++++++----------------- tests/properties.cc | 95 ++++++++++++----- 2 files changed, 261 insertions(+), 115 deletions(-) Index: metalic/tests/properties.cc --- metalic/tests/properties.cc (revision 413) +++ metalic/tests/properties.cc (working copy) @@ -14,22 +14,23 @@ namespace my { - /*----------------------. - | Namespace equipment. | - `----------------------*/ - - mlc_equip_namespace_with_properties(); - - /*-----------. | Typedefs. | `-----------*/ - mlc_decl_typedef(ptr_type); mlc_decl_typedef(foo_type); mlc_decl_typedef(bar_type); mlc_decl_typedef(baz_type); mlc_decl_typedef(quux_type); + mlc_decl_typedef(yin_type); + mlc_decl_typedef(zorg_type); + + + /*----------------------. + | Namespace equipment. | + `----------------------*/ + + mlc_equip_namespace_with_properties(); /*-----------. @@ -43,7 +44,6 @@ } - /*----. | A. | `----*/ @@ -51,10 +51,9 @@ // Forward declaration. struct A; - // FIXME: Rename as set_types<> when mlc/properties.hh is updated. - // Associated types. + /// Types associated to my::A. template<> - struct set_types<category::my_cat, my::A> + struct vtypes<category::my_cat, my::A> { typedef int foo_type; typedef float bar_type; @@ -80,47 +79,93 @@ // Warning, this sugar might me remove from properties.hh. mlc_set_super(B, A); - /// \brief Redefined types associated to \a B. - /// - /// Keeping the inheritance is absolutely capital here (i.e., when - /// you redefine an associated type with redefine_types). + /// Types associated to my::B. template<> - struct redefine_types<category::my_cat, B> : - mlc_super_types_(category::my_cat, B) + struct vtypes<category::my_cat, B> { + // (foo is left untouched.) + // A type redefined here. typedef double bar_type; // A type defined here (but declared abstract in the super class). typedef char baz_type; + // A type defined only here (and not in the super class). + typedef long quux_type; }; - /// \brief New types associated to \a B. + /// An external type associated to my::B. template<> - struct set_types<category::my_cat, B> + struct ext_vtype<category::my_cat, B, typedef_::yin_type> { - // A type defined only here (and not in the super class). - typedef long quux_type; + typedef unsigned long ret; }; - struct B : public mlc_super(B) + struct B : public mlc_super_(B) { // Aliases. typedef my_type_of_(B, foo) foo_type; typedef my_type_of_(B, bar) bar_type; typedef my_type_of_(B, baz) baz_type; typedef my_type_of_(B, quux) quux_type; + typedef my_type_of_(B, yin) yin_type; }; + + + /*---. + | C. | + `---*/ + + // Forward declaration. + struct C; + + // C do not derive from B, but we want its vtypes to ``inherit'' + // from B's vtypes (see the specilization + // vtypes<category::my_cat, C>. + + /// Types associated to my::C. + template<> + struct vtypes<category::my_cat, C> + { + // FIXME: Having this link here is not elegant when you consider + // ext_vtype<>: this means that even if you have only a vtype + // declared as ext_vtype, you'll still have to define a + // corresponding vtypes<>, at least to define the pseudosuper + // class. What about externalizing this information, maybe with + // set_pseudosuper_type<>, and a macro set_pseudosuper() as sugar? + + /// Link to B (``pseudo'' inheritance). + typedef B pseudosuper_type; + + // A type defined only here (and not in the super class). + typedef double zorg_type; + }; + + struct C // no inheritance + { + // Aliases. + typedef my_type_of_(C, foo) foo_type; + typedef my_type_of_(C, quux) quux_type; + typedef my_type_of_(C, zorg) zorg_type; + }; + } + int main() { - // Check associated types. + // Check types associated to A. mlc_eq(my::A::foo_type, int)::ensure (); mlc_eq(my::A::bar_type, float)::ensure (); - // Check associated types. + // Check types associated to B. mlc_neq(my::B::bar_type, my::A::bar_type)::ensure (); mlc_eq(my::B::baz_type, char)::ensure (); mlc_eq(my::B::quux_type, long)::ensure (); + mlc_eq(my::B::yin_type, unsigned long)::ensure (); + + // Check types associated to C. + mlc_eq(my::C::foo_type, int)::ensure (); + mlc_eq(my::C::quux_type, long)::ensure (); + mlc_eq(my::C::zorg_type, double)::ensure (); } Index: metalic/mlc/properties.hh --- metalic/mlc/properties.hh (revision 413) +++ metalic/mlc/properties.hh (working copy) @@ -52,9 +52,21 @@ // FIXME: Add support for hierarchies with several super classes. # define mlc_equip_namespace_with_properties() \ \ - /* ------------------------- */ \ - /* Inheritance declaration. */ \ - /* ------------------------- */ \ + /* ----------------------- */ \ + /* Typedefs declarations. */ \ + /* ----------------------- */ \ + \ + /* FIXME: Should we use the `ret' typdef defined in the global */ \ + /* namespace instead ? (see at the end mlc/typedef.hh). */ \ + mlc_decl_typedef(ret); \ + \ + /* Declare the ``uplink'' typedef (access to a pseudosuper class). */ \ + mlc_decl_typedef(pseudosuper_type); \ + \ + \ + /* ------------- */ \ + /* Inheritance. */ \ + /* ------------- */ \ \ template <typename type> \ struct set_super_type \ @@ -63,58 +75,36 @@ }; \ \ \ - /* ---------------------------------------- */ \ - /* ``Internal'' associated types facility. */ \ - /* ---------------------------------------- */ \ + /* --------------- */ \ + /* Virtual types. */ \ + /* --------------- */ \ \ - /** Fwd decl. */ \ - namespace internal { \ - template <typename category, typename from_type> struct get_types; \ - } \ - \ - /** Specialize this class to set ``internal'' associated types. */ \ + /** \brief Internal virtual types associated to \a from_type. */ \ + /** */ \ + /** Specialize this class for the desired \a from_type. */ \ template <typename category, typename from_type> \ - struct set_types \ + struct vtypes \ { \ }; \ \ - /** \brief Specialize this class to redefine ``internal'' */ \ - /** associated types. */ \ - /** */ \ - /** Notice the inheritance relation, which enable the automatic */ \ - /** retrieval of the types associated to the super class of \a */ \ - /** from_type. */ \ - template <typename category, typename from_type> \ - struct redefine_types : public mlc_super_types(category, from_type) \ + /** End of the recursive construction of any vtypes hierarchy. */ \ + template <typename category> \ + struct vtypes<category, mlc::none> \ { \ }; \ \ - \ - /* ----------------------------------------- */ \ - /* ``External'' associated types machinery. */ \ - /* ----------------------------------------- */ \ - \ - /** Fwd decl. */ \ - namespace internal { \ - template <typename category, typename from_type, typename typedef_type> \ - struct get_ext_type; \ - } \ - \ - /** Specialize this class to set an ``external'' associated type. */ \ + /** \brief An external virtual type associated to \a from_type. */ \ + /** */ \ + /** Specialize this class for the desired \a from_type. */ \ template <typename category, typename from_type, typename typedef_type> \ - struct set_ext_type \ + struct ext_vtype \ { \ }; \ \ - /** \brief Specialize this class to redefine an ``external'' */ \ - /** associated type. */ \ - /** */ \ - /** Notice the inheritance relation, which enable the automatic */ \ - /** retrieval of the types associated to the super class of \a */ \ - /** from_type. */ \ - template <typename category, typename from_type, typename typedef_type> \ - struct redefine_ext_type : \ - public mlc_super_ext_type(category, from_type, typedef_type) \ + /** End of the recursive construction of any ext_vtype<> */ \ + /** hierarchy. */ \ + template <typename category, typename typedef_type> \ + struct ext_vtype<category, mlc::none, typedef_type> \ { \ }; \ \ @@ -128,34 +118,162 @@ /** retrieval mechanism). */ \ namespace internal \ { \ - template <typename category, typename from_type> \ - struct get_types : \ - public set_types<category, from_type>, \ - public redefine_types<category, from_type> \ + /* ------------------------------------------ */ \ + /* Recursive retrieval of an internal vtype. */ \ + /* ------------------------------------------ */ \ + \ + /* FIXME: Do a basic scheme of the algorithm in pseudo-code. */ \ + \ + /* FIXME: Check for mlc::undefined? */ \ + \ + /* FIXME: The presence of `vtypes' is the only thing that makes */ \ + /* this code different from the retrieval within an external */ \ + /* vtype. How can we factor this? */ \ + template <typename category, typename from_type, typename typedef_type> \ + struct rec_get_vtype \ { \ + /** Set of vtypes associated with FROM_TYPE. */ \ + typedef vtypes<category, from_type> types; \ + /** Typedef in the current vtypes (maybe mlc::not_found). */ \ + typedef mlc_internal_get_typedef(types, typedef_type) type; \ + \ + /** Implicit parent (i.e. super), if any. */ \ + typedef mlc_super(from_type) super; \ + /** Pseudosuper class, if any. */ \ + typedef mlc_internal_get_typedef(types, typedef_::pseudosuper_type) \ + pseudosuper; \ + \ + typedef typename \ + mlc::if_< \ + mlc::neq_< type, mlc::not_found >, \ + /* then */ \ + /* return it */ \ + /* (the typedef has been found in the vtypes */ \ + /* associated to FROM_TYPE) */ \ + type, \ + /* else */ \ + /* check if the vtype of the `super' of FROM_TYPE */ \ + /* has the typedef */ \ + typename \ + mlc::if_< mlc::neq_< typename rec_get_vtype< category, \ + super, \ + typedef_type >::ret, \ + mlc::not_found >, \ + /* then */ \ + /* return it */ \ + typename rec_get_vtype< category, \ + super, \ + typedef_type >::ret, \ + /* else */ \ + /* check if the FROM_TYPE has a decl_parent */ \ + /* and try to retrieve the typedef from it. */ \ + typename rec_get_vtype< category, \ + pseudosuper, \ + typedef_type >::ret >::ret >::ret \ + ret; \ }; \ \ - /** End of the recursive construction of any get_types<> hierarchy. */ \ - template <typename category> \ - struct get_types<category, mlc::none> \ + /** Ends of the recursive retrieval (mlc::none is at the end of the */ \ + /** transitive closure of every `super' relation). */ \ + /** \{ */ \ + /** Case where \a from_type = mlc::none (end of a recursive */ \ + /** retrieval following `super' types). */ \ + template <typename category, typename typedef_type> \ + struct rec_get_vtype<category, mlc::none, typedef_type> \ + { \ + typedef mlc::not_found ret; \ + }; \ + /** Case where \a from_type = mlc::not_found (end of a recursive */ \ + /** retrieval following `super' types). */ \ + template <typename category, typename typedef_type> \ + struct rec_get_vtype<category, mlc::not_found, typedef_type> \ { \ + typedef mlc::not_found ret; \ }; \ + /** \} */ \ + \ + /* ------------------------------------------ */ \ + /* Recursive retrieval of an external vtype. */ \ + /* ------------------------------------------ */ \ + \ + /* FIXME: Merge this with rec_get_vtype. */ \ \ template <typename category, typename from_type, typename typedef_type> \ - struct get_ext_type : \ - public set_ext_type<category, from_type, typedef_type>, \ - public redefine_ext_type<category, from_type, typedef_type> \ + struct rec_get_ext_vtype \ { \ + /** Set of vtypes associated with FROM_TYPE. */ \ + typedef ext_vtype<category, from_type, typedef_type> ext_type; \ + /** Typedef in the current vtypes (maybe mlc::not_found). */ \ + typedef mlc_internal_get_typedef(ext_type, typedef_::ret) type; \ + \ + /** Implicit parent (i.e. super), if any. */ \ + typedef mlc_super(from_type) super; \ + /** Pseudosuper class, if any. */ \ + /* FIXME: Looking for this information is not elegant. Have a */ \ + /* look at metalic/tests/properties.cc for a better suggestion. */ \ + typedef vtypes<category, from_type> types; \ + typedef mlc_internal_get_typedef(types, typedef_::pseudosuper_type) \ + pseudosuper; \ + \ + typedef typename \ + mlc::if_< \ + mlc::neq_< type, mlc::not_found >, \ + /* then */ \ + /* return it */ \ + /* (the typedef has been found in the vtypes */ \ + /* associated to FROM_TYPE) */ \ + type, \ + /* else */ \ + /* check if the vtype of the `super' of FROM_TYPE */ \ + /* has the typedef */ \ + typename \ + mlc::if_< mlc::neq_< typename rec_get_ext_vtype< category, \ + super, \ + typedef_type >::ret, \ + mlc::not_found >, \ + /* then */ \ + /* return it */ \ + typename rec_get_ext_vtype< category, \ + super, \ + typedef_type >::ret, \ + /* else */ \ + /* check if the FROM_TYPE has a decl_parent */ \ + /* and try to retrieve the typedef from it. */ \ + typename rec_get_ext_vtype< category, \ + pseudosuper, \ + typedef_type >::ret>::ret>::ret \ + ret; \ }; \ \ - /** End of the recursive construction of any get_ext_type<> */ \ - /** hierarchy. */ \ + /** Ends of the recursive retrieval (mlc::none is at the end of the */ \ + /** transitive closure of every `super' relation). */ \ + /** \{ */ \ + /** Case where \a from_type = mlc::none (end of a recursive */ \ + /** retrieval following `super' types). */ \ + template <typename category, typename typedef_type> \ + struct rec_get_ext_vtype<category, mlc::none, typedef_type> \ + { \ + typedef mlc::not_found ret; \ + }; \ + /** Case where \a from_type = mlc::not_found (end of a recursive */ \ + /** retrieval following `super' types). */ \ template <typename category, typename typedef_type> \ - struct get_ext_type<category, mlc::none, typedef_type> \ + struct rec_get_ext_vtype<category, mlc::not_found, typedef_type> \ { \ + typedef mlc::not_found ret; \ }; \ + /** \} */ \ + \ + /* ------------------------------------- */ \ + /* External/internal typedef selection. */ \ + /* ------------------------------------- */ \ \ - /** Typedef selector. */ \ + /** \brief Typedef selector. */ \ + /** */ \ + /** A virtual type is considered valid if and only if it has been */ \ + /** found as an internal vtype or (exclusive) as an external vtype. */ \ + /** Other cases (no definition or a double definition) are invalid. */ \ + /** */ \ /** \{ */ \ /** Fwd decl. */ \ template <bool external_typedef_p, bool internal_typedef_p, \ @@ -196,26 +314,21 @@ } /** End of namespace internal. */ \ \ \ - /** FIXME: Don't query from_type directly, but */ \ - /** exact_type(from_type) instead */ \ + /* FIXME: Don't query from_type directly, but exact_type(from_type) */ \ + /* instead. We need mlc::any for this. */ \ template <typename category, typename from_type, typename typedef_type> \ struct typeof_ \ { \ - typedef internal::get_types<category, from_type> types; \ - /* FIXME: Add a check in typeof_ to ensure that get_ext_type */ \ - /* derives from get_ext_type<none> */ \ - typedef \ - internal::get_ext_type<category, from_type, typedef_type> ext_type; \ - /* FIXME: Add a check in typeof_ to ensure that get_ext_type */ \ - /* derives from get_ext_type<none> */ \ - \ - /** Look for the typedef as an external type. */ \ - typedef \ - mlc_internal_get_typedef(ext_type, typedef_::ret) external_typedef; \ - /** Look for the typedef in internal types. */ \ - typedef \ - mlc_internal_get_typedef(types, typedef_type) internal_typedef; \ + /* Look for the typedef as an external type. */ \ + typedef typename \ + internal::rec_get_ext_vtype<category, from_type, typedef_type>::ret \ + external_typedef; \ + /* Look for the typedef in internal types. */ \ + typedef typename \ + internal::rec_get_vtype<category, from_type, typedef_type>::ret \ + internal_typedef; \ \ + /* Did we found the virtual type? */ \ static const bool found_external_p = \ mlc::is_found<external_typedef>::value; \ static const bool found_internal_p = \ @@ -243,25 +356,13 @@ typedef Super ret; \ } -/// \def Get the immediate base class of T +/// \def Get the immediate base class of T (version with typename). # define mlc_super(T) \ - set_super_type<T>::ret + typename set_super_type<T>::ret -// FIXME: Doc. -# define mlc_super_types(Category, FromType) \ - internal::get_types<Category, typename mlc_super(FromType)> - -// FIXME: Doc. -# define mlc_super_types_(Category, FromType) \ - internal::get_types<Category, mlc_super(FromType)> - -// FIXME: Doc. -# define mlc_super_ext_type(Category, FromType, Typedef) \ - internal::get_ext_type<Category, typename mlc_super(FromType), Typedef> - -// FIXME: Doc. -# define mlc_super_ext_type_(Category, FromType, Typedef) \ - internal::get_ext_type<Category, mlc_super(FromType), Typedef> +/// \def Get the immediate base class of T (version without typename). +# define mlc_super_(T) \ + set_super_type<T>::ret /// Get the property \a Typedef from \a FromType (version with typename). #define mlc_typeof(Category, FromType, Typedef) \