https://svn.lrde.epita.fr/svn/oln/trunk/metalic Index: ChangeLog from Thierry Geraud <theo@lrde.epita.fr> Add documentation. * mlc/is_a.hh (wrap): Move to... * mlc/wrap.hh: ...this new file. * mlc/bool.hh (ensure_): Take just one parameter; the former variadic version is now handled by... (ensure_list_): ...this new class. * mlc/typedef.hh: Rename some internals. bool.hh | 65 +++++++++++-- is_a.hh | 160 +++++++++++++++++++------------- typedef.hh | 297 ++++++++++++++++++++++++++++++------------------------------- wrap.hh | 121 ++++++++++++++++++++++++ 4 files changed, 422 insertions(+), 221 deletions(-) Index: mlc/wrap.hh --- mlc/wrap.hh (revision 0) +++ mlc/wrap.hh (revision 0) @@ -0,0 +1,121 @@ +// Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006 EPITA Research and Development Laboratory +// +// This file is part of the Olena Library. This library is free +// software; you can redistribute it and/or modify it under the terms +// of the GNU General Public License version 2 as published by the +// Free Software Foundation. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this library; see the file COPYING. If not, write to +// the Free Software Foundation, 59 Temple Place - Suite 330, Boston, +// MA 02111-1307, USA. +// +// As a special exception, you may use this file as part of a free +// software library without restriction. Specifically, if other files +// instantiate templates or use macros or inline functions from this +// file, or you compile this file and link it with other files to +// produce an executable, this file does not by itself cause the +// resulting executable to be covered by the GNU General Public +// License. This exception does not however invalidate any other +// reasons why the executable file might be covered by the GNU General +// Public License. + +#ifndef METALIC_WRAP_HH +# define METALIC_WRAP_HH + + +namespace mlc +{ + /*! \class mlc::wrap<T> + ** + ** This class is a workaround to the problem of implicit typename + ** that appears when writting something like: + ** outer_struct::inner_struct::value + ** + ** Instead of solving manually this problem with: + ** typedef typename outer_struct::inner_struct temp; + ** temp::value + ** you can write directly: + ** wrap< typename outer_struct::inner_struct >::value + ** + ** This class is used by the mlc_is_a macro. + ** + ** Design note: a detailed example can be read at the end of + ** the file mlc/wrap.hh + */ + + template <class T> + struct wrap : public T + { + typedef T unwrap; + }; + +} // end of namespace mlc + + +/* + +// FIXME: the code below is weird! I didn't succeed in reproducing +// the limitation of the "implicit typename" error; see the comment in +// code... + +#include <iostream> +#include <mlc/bool.hh> + +template <class T> struct wrap : public T {}; + +namespace my +{ + template <class T, T val> + struct value_ + { + static const T value = val; + }; + + template <bool b> + struct value_ <bool, b> + { + static const bool value = b; + }; + + template <bool b> + struct bool_; + + template <> + struct bool_<true> : public value_<bool, true> + { + }; + + typedef bool_<true> true_; +} + +template <class T> +struct outer +{ + struct inner_struct + : public my::true_ { + // replacing "my" by "mlc" gives an error (see KO below) and I + // don't understand why! + }; +}; + +template <class T> +void foo_() +{ + std::cout << outer<T>::inner_struct::value << std::endl; // KO +} + +int main() +{ + foo_<int>(); +} + +*/ + + +#endif // ! METALIC_WRAP_HH Index: mlc/bool.hh --- mlc/bool.hh (revision 387) +++ mlc/bool.hh (working copy) @@ -190,7 +190,56 @@ - /*! \class mlc::ensure_<expr1..> + /*! \class mlc::ensure_<expr> + ** + ** This class is a replacement for the instruction "expr::ensure();" + ** when there is no room for having instruction. The typical use + ** is to express a constraint (or several constraints) upon a + ** parameter (or several parameters) of a templated class. + ** + ** ensure_<expr> only accepts one parameter, which has to be a + ** Boolean expression type. An equivalent version for a variadic + ** list of parameters is ensure_list_<expr1,..> + ** + ** Sample uses: + ** + ** template <class T> + ** struct dummy : private ensure_< neq_<T, int> > + ** { ... + ** }; + ** means that T can be any type but int. + ** + ** template <class T1, class T2> + ** struct dummy2 : private ensure_< neq_<T1, int> >, + ** private ensure_< neq_<T2, float> > + ** { ... + ** }; + ** means that T1 should not be int and that T2 should not be float. + ** This last example is equivalent to: + ** template <class T1, class T2> + ** struct dummy2 : private ensure_list_< neq_<T1, int>, + ** neq_<T2, float> > + ** { ... + ** }; + ** + ** Design notes: 1) This class does not derive from abstract::type + ** because it is used in inheritance so a ctor should exist. 2) + ** This class relies on mlc::internal::ensure_item to check that + ** the expression is true. + ** + ** \see ensure_list_<expr1,..> + ** + */ + + template <typename expr> + struct ensure_ : + private internal::ensure_item<0, typename expr::internal_ensure_> + { + }; + + + + /*! \class mlc::ensure_list_<expr1..> ** ** This class is a replacement for a sequence of instructions: ** "expr1::ensure(); .." when there is no room for having @@ -198,9 +247,10 @@ ** several constraints) upon a parameter (or several parameters) ** of a templated class. ** - ** ensure_<..> has a variadic list of parameters. It expects at - ** least one parameter and handles up to 9 parameters. Each parameter - ** has to be a Boolean expression type. + ** ensure_list_<..> has a variadic list of parameters. It expects + ** at least 2 parameters and handles up to 9 parameters. Each + ** parameter has to be a Boolean expression type. To check only a + ** single expression, the appropriate tool is ensure_<expr>. ** ** Sample uses: ** @@ -217,7 +267,7 @@ ** }; ** is equivalent to: ** template <class T1, class T2> - ** struct dummy2 : private ensure_< neq_<T1, int>, + ** struct dummy2 : private ensure_list< neq_<T1, int>, ** neq_<T2, int> > ** { ... ** }; @@ -227,10 +277,11 @@ ** This class relies on mlc::internal::ensure_item to check that ** each expression is true. ** + ** \see ensure_<expr> */ template <typename expr_1, - typename expr_2 = internal::none_, + typename expr_2, typename expr_3 = internal::none_, typename expr_4 = internal::none_, typename expr_5 = internal::none_, @@ -238,7 +289,7 @@ typename expr_7 = internal::none_, typename expr_8 = internal::none_, typename expr_9 = internal::none_> - struct ensure_ : + struct ensure_list_ : private internal::ensure_item<1, typename expr_1::internal_ensure_>, private internal::ensure_item<2, typename expr_2::internal_ensure_>, private internal::ensure_item<3, typename expr_3::internal_ensure_>, Index: mlc/is_a.hh --- mlc/is_a.hh (revision 387) +++ mlc/is_a.hh (working copy) @@ -29,37 +29,25 @@ # define METALIC_IS_A_HH # include <mlc/bool.hh> +# include <mlc/wrap.hh> - -// internal macro so do not use it -# define mlc_internal_is_a__check_result_ \ -sizeof(helper<T ,U >::check( (T *) helper<T,U >::makeT() )) == sizeof(mlc::internal::yes_) +// private macro so do _not_ use it +# define mlc_internal_is_a_result_ \ +sizeof(helper<T,U>::select((T*)helper<T,U>::makeT())) == sizeof(yes_) namespace mlc { - namespace internal - { - - // - // wrap is a workaround to fix g++-2.95 problem with implicit: - // instead of typename in <foo<T>::ret::dim> - // write <wrap<typename foo<T>::ret>::dim - template <class T> struct wrap : public T {}; - - - /// form - namespace form { enum { class_ = 1, - template_l_class_g_class_ = 2, - template_l_class_class_g_class_ = 3, - template_l_template_l_class_g_class_g_class_ = 4, - template_l_template_l_class_class_g_class_g_class_ = 5 + template_l_class_r_class_ = 2, + template_l_class_class_r_class_ = 3, + template_l_template_l_class_r_class_r_class_ = 4, + template_l_template_l_class_class_r_class_r_class_ = 5 // ... }; @@ -68,160 +56,200 @@ { char dummy[id]; }; template < class T> - static desc< class_ > get(); + static desc< class_ > of(); template < template < class > class T> - static desc< template_l_class_g_class_ > get(); + static desc< template_l_class_r_class_ > of(); template< template < class,class > class T> - static desc< template_l_class_class_g_class_ > get(); + static desc< template_l_class_class_r_class_ > of(); template< template < template < class > class > class T> - static desc< template_l_template_l_class_g_class_g_class_ > get(); + static desc< template_l_template_l_class_r_class_r_class_ > of(); template< template < template < class,class > class > class T> - static desc< template_l_template_l_class_class_g_class_g_class_ > get(); + static desc< template_l_template_l_class_class_r_class_r_class_ > of(); // ... - } // end of namespace mlc::internal::form + } // end of namespace mlc::form + namespace internal + { + typedef char yes_; struct no_ { char dummy[2]; }; - // dev note : below, is_a_<T,id> is a better factorization + // dev note : below, is_a<T,id> is a better factorization // but g++ 2.95.4 has some trouble with it template<unsigned id> - struct is_a_; + struct is_a; // class_ template<> - struct is_a_< form::class_ > + struct is_a< form::class_ > { - typedef is_a_< form::class_ > self; + typedef is_a< form::class_ > self; template<class T, class U> struct helper { - static yes_ check(U*); - static no_ check(...); + static yes_ select(U*); + static no_ select(...); static T* makeT(); }; template<class T, class U> - struct check - : public bool_<( mlc_internal_is_a__check_result_ )> + struct ret + : public bool_<( mlc_internal_is_a_result_ )> { }; }; - // template_l_class_g_class_ + // template_l_class_r_class_ template<> - struct is_a_< form::template_l_class_g_class_ > + struct is_a< form::template_l_class_r_class_ > { - typedef is_a_< form::template_l_class_g_class_ > self; + typedef is_a< form::template_l_class_r_class_ > self; template<class T, template < class > class U> struct helper { template<class V> - static yes_ check(U<V>*); - static no_ check(...); + static yes_ select(U<V>*); + static no_ select(...); static T* makeT(); }; template<class T, template < class > class U> - struct check - : public bool_<( mlc_internal_is_a__check_result_ )> + struct ret + : public bool_<( mlc_internal_is_a_result_ )> { }; }; - // template_l_class_class_g_class_ + // template_l_class_class_r_class_ template<> - struct is_a_< form::template_l_class_class_g_class_ > + struct is_a< form::template_l_class_class_r_class_ > { - typedef is_a_< form::template_l_class_class_g_class_ > self; + typedef is_a< form::template_l_class_class_r_class_ > self; template<class T, template < class,class > class U> struct helper { template<class V, class W> - static yes_ check(U<V,W>*); - static no_ check(...); + static yes_ select(U<V,W>*); + static no_ select(...); static T* makeT(); }; template<class T, template < class,class > class U> - struct check - : public bool_<( mlc_internal_is_a__check_result_ )> + struct ret + : public bool_<( mlc_internal_is_a_result_ )> {}; }; - // template_l_template_l_class_g_class_g_class_ + // template_l_template_l_class_r_class_r_class_ template<> - struct is_a_< form::template_l_template_l_class_g_class_g_class_ > + struct is_a< form::template_l_template_l_class_r_class_r_class_ > { - typedef is_a_< form::template_l_template_l_class_g_class_g_class_ > self; + typedef is_a< form::template_l_template_l_class_r_class_r_class_ > self; template<class T, template < template < class > class > class U> struct helper { template<template<class> class V> - static yes_ check(U<V>*); - static no_ check(...); + static yes_ select(U<V>*); + static no_ select(...); static T* makeT(); }; template<class T, template < template < class > class > class U> - struct check - : public bool_<( mlc_internal_is_a__check_result_ )> + struct ret + : public bool_<( mlc_internal_is_a_result_ )> {}; }; - // template_l_template_l_class_class_g_class_g_class_ + // template_l_template_l_class_class_r_class_r_class_ template<> - struct is_a_< form::template_l_template_l_class_class_g_class_g_class_ > + struct is_a< form::template_l_template_l_class_class_r_class_r_class_ > { - typedef is_a_< form::template_l_template_l_class_class_g_class_g_class_ > self; + typedef is_a< form::template_l_template_l_class_class_r_class_r_class_ > self; template<class T, template < template < class,class > class > class U> struct helper { template<template<class,class> class V> - static yes_ check(U<V>*); - static no_ check(...); + static yes_ select(U<V>*); + static no_ select(...); static T* makeT(); }; template<class T, template < template < class,class > class > class U> - struct check - : public bool_<( mlc_internal_is_a__check_result_ )> + struct ret + : public bool_<( mlc_internal_is_a_result_ )> {}; }; - } // end of namespace mlc::internal } // end of namespace mlc -/// Client macro mlc_is_a(T, U) +/*! \macro mlc_is_a(T, U) +** +** Macro that answers if T is an U. T should be a type and U can have +** different forms: class, template class, etc. The result is a +** Boolean expression type. +** +** Sample use: With: +** template <class B> struct base {}; +** struct derived : public base<int> {}; +** the expression mlc_is_a(derived, base) derives from mlc::true_. +** A constraint on the parameter of a class, which should be any +** subclass of base<B>, whatever B, can then be easily written: +** template <class T> +** struct foo : private mlc::ensure_< mlc_is_a(T, base) > { +** // ... +** }; +** +** Limitations: 1) When U is a template class defined with a default +** parameter, the form of U is ambiguous. For instance, with the +** definition "template <class P1, class P2 = P1> struct foo {};", foo +** can be considered as well as a "template<class> class" and as a +** "template <class, class> class. The call mlc_is_a(T, foo) is thus +** ambiguous. 2) The forms of U that are handled by the meta-program +** behind the macro are limited to the few cases listed below: +** class +** template < class > class +** template < class, class > class +** template < template < class > class > class +** template < template < class, class > class > class +*/ # define mlc_is_a(T, U) \ -mlc::internal::wrap<typename mlc::internal::is_a_< sizeof(mlc::internal::form::get<U >()) >::check<T, U > > +mlc::wrap<typename mlc::internal::is_a<sizeof(mlc::form::of<U >())>::ret<T,U > > + + +/*! \macro mlc_is_a_(T, U) +** +** Macro equivalent as mlc_is_a(T, U) for use in a non templated +** context. The result is a Boolean expression type. +** +** \see mlc_is_a(T, U) +*/ # define mlc_is_a_(T, U) \ -mlc::internal::wrap< mlc::internal::is_a_< sizeof(mlc::internal::form::get<U >()) >::check<T, U > > +mlc::wrap<mlc::internal::is_a< sizeof(mlc::form::of<U >())>::ret<T,U > > #endif // ! METALIC_IS_A_HH Index: mlc/typedef.hh --- mlc/typedef.hh (revision 387) +++ mlc/typedef.hh (working copy) @@ -28,210 +28,211 @@ #ifndef METALIC_TYPEDEF_HH # define METALIC_TYPEDEF_HH -# include <mlc/types.hh> +# include <mlc/flags.hh> # include <mlc/bool.hh> -// do not use the macro below if you equip a namespace with properties - -# define mlc_equip_namespace_with_typedef() \ -namespace internal \ -{ \ - \ - template <typename type, typename typedef_type> \ - struct get_typedef \ - { \ - typedef mlc::internal::not_found ret; \ - }; \ - \ - template <typename type, typename typedef_type, typename cond> \ - struct get_typedef_onlyif \ - { \ - typedef mlc::internal::not_found ret; \ - }; \ - \ -} \ -struct e_n_d__w_i_t_h__s_e_m_i_c_o_l_o_n - - - - /*! \macro mlc_decl_typedef (TypedefName) ** -** Macro to equip mlc with a static mechanism for a typedef retrieval. +** This macro is for declaring the use of a typedef embedded in +** classes. After having declaring a typedef, accessing the typedef +** is performed through the mlc_typedef macro. The main difference +** between the classic access, "Type::TypedefName", and its +** equivalent, "mlc_typedef(Type, TypedefName)", is that the latter +** also works when the access is ill-formed. Put differently, +** mlc_typedef also works when Type does not have TypedefName in its +** interface; the result is then the special type mlc::not_found. +** +** +** Sample use: Let us declare the "value_type" typedef name in the +** global namespace. +** +** mlc_decl_typedef(value_type); +** +** The following couple of typedef access: +** +** typename std::vector<int>::value_type +** mlc_typedef(std::vector<int>, value_type) +** +** are exactly equivalent and give "int" as result. However, with +** "type" being "std::pair<int, int>", the access: +** +** typename type::value_type +** +** is invalid and does not compile (because there is no value_type +** defined in the interface of std::pair), wheras the replacement +** access: +** +** mlc_typedef(type, value_type) +** +** does compile and gives mlc::not_found. +** +** +** When the declaration mlc_decl_typedef is located in a particular +** namespace, mlc_typedef can be used within this namespace and its +** sub-namespaces. However, it is highly recommended to define a +** particular access macro if you want to call mlc_typedef from +** another namespace (the global one for instance). +** +** namespace my { +** +** struct foo { +** typedef float value_type; +** }; +** +** mlc_decl_typedef(value_type); +** +** namespace sub { +** +** template <class T> +** void bar() +** { +** mlc_typedef(foo, value_type) tmp; // ok +** } +** +** } // end of namespace my::sub +** +** } // end of namespace my +** +** int main() +** { +** { +** mlc_typedef_(my::foo, value_type) tmp; // KO +** } +** { +** using my::typedef_; +** mlc_typedef_(my::foo, value_type) tmp; // ok +** } +** } +** +** better: +** +** #define my_typedef(Type, TypedefName) mlc_typedef_in(my, Type, TypedefName) +** #define my_typedef_(Type, TypedefName) mlc_typedef_in_(my, Type, TypedefName) ** -** FIXME +** and then: +** +** int main() +** { +** my_typedef_(my::foo, value_type) tmp; // ok +** } +** +** +** Design notes: +** The declaration of a typedef name leads to the creation of the type +** "typedef_::TypedefName" located in the namespace where the +** declaration has been performed. This type can be used as a flag to +** designate a particular class typedef, whatever the classes it can +** be applied to. +** +** \see mlc_typedef(Type, TypedefName) */ # define mlc_decl_typedef(TypedefName) \ -namespace internal \ -{ \ \ - namespace typedef_ \ - { \ - struct TypedefName; \ - } \ +namespace typedef_ { \ + \ + namespace internal { \ \ - struct helper_get_typedef__##TypedefName \ + struct TypedefName \ { \ typedef char yes; \ struct no { char tmp[2]; }; \ \ - template <typename type, typename alias = typename type::TypedefName> \ + template <class T, \ + typename alias = typename T::TypedefName> \ struct run_on; \ \ - template <typename type> \ - static yes selector(run_on<type>*); \ + template <class T> \ + static yes selector(run_on<T>*); \ \ - template <typename type> \ + template <class T> \ static no selector(...); \ \ - template <typename type, bool found> \ + template <class T, bool found> \ struct result; \ \ - template <typename type> \ - struct result <type, true> \ - { \ - typedef typename type::TypedefName ret; \ + template <class T> \ + struct result <T, true> { \ + typedef typename T::TypedefName ret; \ }; \ \ - template <typename type> \ - struct result <type, false> \ - { \ - typedef mlc::internal::not_found ret; \ - }; \ + template <class T> \ + struct result <T, false> { \ + typedef mlc::not_found ret; \ }; \ \ - template <typename type> \ - struct get_typedef__##TypedefName \ - { \ - typedef helper_get_typedef__##TypedefName helper_type; \ - static const bool found = ( sizeof(helper_type::selector<type>(0)) == 1 ); \ - typedef typename helper_type::result<type, found>::ret ret; \ }; \ \ - template <typename type> \ - struct get_typedef <type, typedef_::TypedefName> \ + } \ + \ + struct TypedefName \ + { \ + template <class T> \ + struct in_ \ { \ - typedef typename get_typedef__##TypedefName <type> ::ret ret; \ + private: \ + typedef internal::TypedefName helper_; \ + enum { \ + found_ = \ + (sizeof(helper_::selector<T>(0)) == 1) \ + }; \ + public: \ + typedef \ + typename helper_::result<T, found_>::ret \ + ret; \ }; \ \ + template <class T, bool b> \ + struct in_onlyif_; \ \ - template <typename type, bool cond> \ - struct helper_get_typedef_onlyif__##TypedefName; \ \ - template <typename type> \ - struct helper_get_typedef_onlyif__##TypedefName <type, false> \ + template <class T> \ + struct in_onlyif_ <T, true> \ { \ - typedef mlc::internal::not_ok ret; \ + typedef typename in_<T>::ret ret; \ }; \ \ - template <typename type> \ - struct helper_get_typedef_onlyif__##TypedefName <type, true> \ + template <class T> \ + struct in_onlyif_ <T, false> \ { \ - typedef typename type::TypedefName ret; \ + typedef mlc::dummy ret; \ }; \ \ - template <typename type, typename cond> \ - struct get_typedef_onlyif__##TypedefName \ - : public helper_get_typedef_onlyif__##TypedefName <type, mlc_bool(cond)> \ - { \ - typedef helper_get_typedef_onlyif__##TypedefName <type, mlc_bool(cond)> super; \ - using super::ret; \ + private: \ + TypedefName() {} \ }; \ \ - template <typename type, typename cond> \ - struct get_typedef_onlyif <type, typedef_::TypedefName, cond> \ - { \ - typedef typename get_typedef_onlyif__##TypedefName <type, cond> ::ret ret; \ - }; \ - \ - \ } \ + \ struct e_n_d__w_i_t_h__s_e_m_i_c_o_l_o_n +/*! \macro mlc_typedef(Type, TypedefName) +** +** FIXME: doc +*/ -// FIXME: mlc should be equipped for typedef retrieval -// FIXME: and should provide at least facilities for 'ret' - -// namespace mlc -// { -// mlc_equip_namespace_with_typedef(); -// mlc_decl_typedef(ret); -// } // end of namespace mlc - - - - -// sample code to understand why mlc_typedef_onlyif_of is required -// in particular situations: - -// #include <mlc/typedef.hh> - -// mlc_equip_namespace_with_typedef(); -// mlc_decl_typedef(ret); - -// struct toto -// { -// typedef float does_not_exist; -// }; - -// template <class T> -// struct ok -// { -// typedef double ret; -// typedef typename T::does_not_exist err; -// }; - -// template <class T> -// struct ko -// { -// }; - -// template <class T> -// void foo() -// { -// typedef mlc_typedef_of(T, ret) type; -// } +#define mlc_typedef(Type, TypedefName) \ + typename typedef_::TypedefName::in_<Type>::ret -// template <class T, class B> -// void bar() -// { -// typedef mlc_typedef_onlyif_of(T, ret, B) type; -// } +#define mlc_typedef_(Type, TypedefName) \ + typedef_::TypedefName::in_<Type>::ret -// int main() -// { -// // code that does not compile: -// // foo< ok<int> >(); -// // bar< ok<int>, mlc::true_type >(); -// // code that works: -// foo< ok<toto> >(); -// bar< ok<toto>, mlc::true_type >(); -// bar< ok<int>, mlc::false_type >(); -// } -/*! \macro mlc_typedef_of( FromType, TypedefName ) +/*! \macro mlc_typedef_onlyif(Type, TypedefName, Bexpr) ** -** FIXME -** Sample use: mlc_typedef_of(std::vector<int>, value_type) +** FIXME: doc */ -# define mlc_typedef_of_(FromType, TypedefName) \ -internal::get_typedef__##TypedefName <FromType>::ret - -# define mlc_typedef_of(FromType, TypedefName) \ -typename mlc_typedef_of_(FromType, TypedefName) - +#define mlc_typedef_onlyif(Type, TypedefName, Bexpr) \ + typename typedef_::TypedefName::in_onlyif_<Type, mlc_bool(Bexpr)>::ret -# define mlc_typedef_onlyif_of_(FromType, TypedefName, Condition) \ -internal::get_typedef_onlyif__##TypedefName <FromType, Condition>::ret +#define mlc_typedef_onlyif_(Type, TypedefName, Bexpr) \ + typedef_::TypedefName::in_onlyif_<Type, mlc_bool(Bexpr)>::ret -# define mlc_typedef_onlyif_of(FromType, TypedefName, Condition) \ -typename mlc_typedef_onlyif_of_(FromType, TypedefName, Condition)
participants (1)
-
Thierry Geraud