/* Metaprogramming utilities. Copyright (C) 2001-2010 Roberto Bagnara Copyright (C) 2010-2011 BUGSENG srl (http://bugseng.com) This file is part of the Parma Polyhedra Library (PPL). The PPL is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. The PPL 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 program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1307, USA. For the most up-to-date information see the Parma Polyhedra Library site: http://www.cs.unipr.it/ppl/ . */ #ifndef PPL_meta_programming_hh #define PPL_meta_programming_hh 1 #include namespace Parma_Polyhedra_Library { #ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS /*! \brief Declares a per-class constant of type bool, called \p name and with value \p value. \ingroup PPL_CXX_interface Differently from static constants, \p name needs not (and cannot) be defined (for static constants, the need for a further definition is mandated by Section 9.4.2/4 of the C++ standard). */ #endif // defined(PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS) #define const_bool_nodef(name, value) \ enum anonymous_enum_ ## name { name = (value) } #ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS /*! \brief Declares a per-class constant of type int, called \p name and with value \p value. \ingroup PPL_CXX_interface Differently from static constants, \p name needs not (and cannot) be defined (for static constants, the need for a further definition is mandated by Section 9.4.2/4 of the C++ standard). */ #endif // defined(PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS) #define const_int_nodef(name, value) \ enum anonymous_enum_ ## name { name = (value) } #ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS /*! \brief Declares a per-class constant of type \p type, called \p name and with value \p value. The value of the constant is accessible by means of the syntax name(). \ingroup PPL_CXX_interface Differently from static constants, \p name needs not (and cannot) be defined (for static constants, the need for a further definition is mandated by Section 9.4.2/4 of the C++ standard). */ #endif // defined(PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS) #define const_value_nodef(type, name, value) \ static type name() { \ return value; \ } #ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS /*! \brief Declares a per-class constant of type \p type, called \p name and with value \p value. A constant reference to the constant is accessible by means of the syntax name(). \ingroup PPL_CXX_interface Differently from static constants, \p name needs not (and cannot) be defined (for static constants, the need for a further definition is mandated by Section 9.4.2/4 of the C++ standard). */ #endif // defined(PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS) #define const_ref_nodef(type, name, value) \ static const type& name() { \ static type name(value); \ return name; \ } #ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS /*! \brief A class that is only defined if \p b evaluates to true. \ingroup PPL_CXX_interface This is the non-specialized case, so the class is declared but not defined. */ #endif // defined(PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS) template struct Compile_Time_Check; #ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS /*! \brief A class that is only defined if \p b evaluates to true. \ingroup PPL_CXX_interface This is the specialized case with \p b equal to true, so the class is declared and (trivially) defined. */ #endif // defined(PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS) template <> struct Compile_Time_Check { }; #define PPL_COMPILE_TIME_CHECK_NAME(suffix) compile_time_check_ ## suffix #define PPL_COMPILE_TIME_CHECK_AUX(e, suffix) \ enum anonymous_enum_compile_time_check_ ## suffix { \ /* If e evaluates to false, then the sizeof cannot be compiled. */ \ PPL_COMPILE_TIME_CHECK_NAME(suffix) \ = sizeof(Parma_Polyhedra_Library:: \ Compile_Time_Check(e)>) \ } #ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS /*! \brief Produces a compilation error if the compile-time constant \p e does not evaluate to true \ingroup PPL_CXX_interface */ #endif // defined(PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS) #define PPL_COMPILE_TIME_CHECK(e, msg) PPL_COMPILE_TIME_CHECK_AUX(e, __LINE__) #ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS /*! \brief A class holding a constant called value that evaluates to \p b. \ingroup PPL_CXX_interface */ #endif // defined(PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS) template struct Bool { enum anonymous_enum { value = b }; }; #ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS /*! \brief A class holding a constant called value that evaluates to true. \ingroup PPL_CXX_interface */ #endif // defined(PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS) struct True : public Bool { }; #ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS /*! \brief A class holding a constant called value that evaluates to false. \ingroup PPL_CXX_interface */ #endif // defined(PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS) struct False : public Bool { }; #ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS /*! \brief A class holding a constant called value that evaluates to true if and only if \p T1 is the same type as \p T2. \ingroup PPL_CXX_interface This is the non-specialized case, in which \p T1 and \p T2 can be different. */ #endif // defined(PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS) template struct Is_Same : public False { }; #ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS /*! \brief A class holding a constant called value that evaluates to true if and only if \p T1 is the same type as \p T2. \ingroup PPL_CXX_interface This is the specialization in which \p T1 and \p T2 are equal. */ #endif // defined(PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS) template struct Is_Same : public True { }; #ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS /*! \brief A class holding a constant called value that evaluates to true if and only if \p Base is the same type as \p Derived or \p Derived is a class derived from \p Base. \ingroup PPL_CXX_interface \note Care must be taken to use this predicate with template classes. Suppose we have \code template struct B; template struct D : public B; \endcode Of course, we cannot test if, for some type variable U, we have Is_Same_Or_Derived, Type>:: anonymous_enum:: value == true. But we can do as follows: \code struct B_Base { }; template struct B : public B_Base; \endcode This enables us to enquire Is_Same_Or_Derived:: anonymous_enum:: value. */ #endif // defined(PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS) template struct Is_Same_Or_Derived { #ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS //! A class that is constructible from just anything. #endif // defined(PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS) struct Any { //! The universal constructor. template Any(const T&); }; //! Overloading with \p Base. static char func(const Base&); //! Overloading with \p Any. static double func(Any); //! A function obtaining a const reference to a \p Derived object. static const Derived& derived_object(); PPL_COMPILE_TIME_CHECK(sizeof(char) != sizeof(double), "architecture with sizeof(char) == sizeof(double)" " (!?)"); enum anonymous_enum { /*! Assuming sizeof(char) != sizeof(double), the C++ overload resolution mechanism guarantees that value evaluates to true if and only if Base is the same type as Derived or Derived is a class derived from Base. */ value = (sizeof(func(derived_object())) == sizeof(char)) }; }; #ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS /*! \brief A class that provides a type member called type equivalent to \p T if and only if \p b is true. \ingroup PPL_CXX_interface This is the non-specialized case, in which the type member is not present. */ #endif // defined(PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS) template struct Enable_If { }; template struct Enable_If_Is { typedef T type; }; #ifdef PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS /*! \brief A class that provides a type member called type equivalent to \p T if and only if \p b is true. \ingroup PPL_CXX_interface This is the specialization in which the type member is present. \note Let T, T1 and T2 be any type expressions and suppose we have some template function T f(T1, T2). If we want to declare a specialization that is enabled only if some compile-time checkable condition holds, we simply declare the specialization by \code template ... typename Enable_If::type foo(T1 x, T2 y); \endcode For all the instantiations of the template parameters that cause condition to evaluate to false, the Enable_If::type member will not be defined. Hence, for that instantiations, the specialization will not be eligible. */ #endif // defined(PPL_DOXYGEN_INCLUDE_IMPLEMENTATION_DETAILS) template struct Enable_If { typedef T type; }; template struct Is_Native : public False { }; template <> struct Is_Native : public True { }; template <> struct Is_Native : public True { }; template <> struct Is_Native : public True { }; template <> struct Is_Native : public True { }; template <> struct Is_Native : public True { }; template <> struct Is_Native : public True { }; template <> struct Is_Native : public True { }; template <> struct Is_Native : public True { }; template <> struct Is_Native : public True { }; template <> struct Is_Native : public True { }; template <> struct Is_Native : public True { }; #if PPL_SUPPORTED_FLOAT template <> struct Is_Native : public True { }; #endif #if PPL_SUPPORTED_DOUBLE template <> struct Is_Native : public True { }; #endif #if PPL_SUPPORTED_LONG_DOUBLE template <> struct Is_Native : public True { }; #endif template <> struct Is_Native : public True { }; template <> struct Is_Native : public True { }; } // namespace Parma_Polyhedra_Library #endif // !defined(PPL_meta_programming_hh)