| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249 | /*!@fileDefines the barebones `boost::hana::integral_constant` template, but nooperations on it.@copyright Louis Dionne 2013-2017Distributed under the Boost Software License, Version 1.0.(See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt) */#ifndef BOOST_HANA_DETAIL_INTEGRAL_CONSTANT_HPP#define BOOST_HANA_DETAIL_INTEGRAL_CONSTANT_HPP#include <boost/hana/config.hpp>#include <boost/hana/detail/operators/adl.hpp>#include <type_traits>BOOST_HANA_NAMESPACE_BEGIN    //! Tag representing `hana::integral_constant`.    //! @relates hana::integral_constant    template <typename T>    struct integral_constant_tag {        using value_type = T;    };    namespace ic_detail {        template <typename T, T v>        struct with_index_t {            template <typename F>            constexpr void operator()(F&& f) const;        };        template <typename T, T v>        struct times_t {            static constexpr with_index_t<T, v> with_index{};            template <typename F>            constexpr void operator()(F&& f) const;        };    }    //! @ingroup group-datatypes    //! Compile-time value of an integral type.    //!    //! An `integral_constant` is an object that represents a compile-time    //! integral value. As the name suggests, `hana::integral_constant` is    //! basically equivalent to `std::integral_constant`, except that    //! `hana::integral_constant` also provide other goodies to make them    //! easier to use, like arithmetic operators and similar features. In    //! particular, `hana::integral_constant` is guaranteed to inherit from    //! the corresponding `std::integral_constant`, and hence have the same    //! members and capabilities. The sections below explain the extensions    //! to `std::integral_constant` provided by `hana::integral_constant`.    //!    //!    //! Arithmetic operators    //! --------------------    //! `hana::integral_constant` provides arithmetic operators that return    //! `hana::integral_constant`s to ease writing compile-time arithmetic:    //! @snippet example/integral_constant.cpp operators    //!    //! It is pretty important to realize that these operators return other    //! `integral_constant`s, not normal values of an integral type.    //! Actually, all those operators work pretty much in the same way.    //! Simply put, for an operator `@`,    //! @code    //!     integral_constant<T, x>{} @ integral_constant<T, y>{} == integral_constant<T, x @ y>{}    //! @endcode    //!    //! The fact that the operators return `Constant`s is very important    //! because it allows all the information that's known at compile-time    //! to be conserved as long as it's only used with other values known at    //! compile-time. It is also interesting to observe that whenever an    //! `integral_constant` is combined with a normal runtime value, the    //! result will be a runtime value (because of the implicit conversion).    //! In general, this gives us the following table    //!    //! left operand        | right operand       | result    //! :-----------------: | :-----------------: | :-----------------:    //! `integral_constant` | `integral_constant` | `integral_constant`    //! `integral_constant` | runtime             | runtime    //! runtime             | `integral_constant` | runtime    //! runtime             | runtime             | runtime    //!    //! The full range of provided operators is    //! - Arithmetic: binary `+`, binary `-`, `/`, `*`, `%`, unary `+`, unary `-`    //! - Bitwise: `~`, `&`, `|`, `^`, `<<`, `>>`    //! - Comparison: `==`, `!=`, `<`, `<=`, `>`, `>=`    //! - %Logical: `||`, `&&`, `!`    //!    //!    //! Construction with user-defined literals    //! ---------------------------------------    //! `integral_constant`s of type `long long` can be created with the    //! `_c` user-defined literal, which is contained in the `literals`    //! namespace:    //! @snippet example/integral_constant.cpp literals    //!    //!    //! Modeled concepts    //! ----------------    //! 1. `Constant` and `IntegralConstant`\n    //! An `integral_constant` is a model of the `IntegralConstant` concept in    //! the most obvious way possible. Specifically,    //! @code    //!     integral_constant<T, v>::value == v // of type T    //! @endcode    //! The model of `Constant` follows naturally from the model of `IntegralConstant`, i.e.    //! @code    //!     value<integral_constant<T, v>>() == v // of type T    //! @endcode    //!    //! 2. `Comparable`, `Orderable`, `Logical`, `Monoid`, `Group`, `Ring`, and `EuclideanRing`, `Hashable`\n    //! Those models are exactly those provided for `Constant`s, which are    //! documented in their respective concepts.#ifdef BOOST_HANA_DOXYGEN_INVOKED    template <typename T, T v>    struct integral_constant {        //! Call a function n times.        //!        //! `times` allows a nullary function to be invoked `n` times:        //! @code        //!     int_<3>::times(f)        //! @endcode        //! should be expanded by any decent compiler to        //! @code        //!     f(); f(); f();        //! @endcode        //!        //! This can be useful in several contexts, e.g. for loop unrolling:        //! @snippet example/integral_constant.cpp times_loop_unrolling        //!        //! Note that `times` is really a static function object, not just a        //! static function. This allows `int_<n>::%times` to be passed to        //! higher-order algorithms:        //! @snippet example/integral_constant.cpp times_higher_order        //!        //! Also, since static members can be accessed using both the `.` and        //! the `::` syntax, one can take advantage of this (loophole?) to        //! call `times` on objects just as well as on types:        //! @snippet example/integral_constant.cpp from_object        //!        //! @note        //! `times` is equivalent to the `hana::repeat` function, which works        //! on an arbitrary `IntegralConstant`.        //!        //! Sometimes, it is also useful to know the index we're at inside the        //! function. This can be achieved by using `times.with_index`:        //! @snippet example/integral_constant.cpp times_with_index_runtime        //!        //! Remember that `times` is a _function object_, and hence it can        //! have subobjects. `with_index` is just a function object nested        //! inside `times`, which allows for this nice little interface. Also        //! note that the indices passed to the function are `integral_constant`s;        //! they are known at compile-time. Hence, we can do compile-time stuff        //! with them, like indexing inside a tuple:        //! @snippet example/integral_constant.cpp times_with_index_compile_time        //!        //! @note        //! `times.with_index(f)` guarantees that the calls to `f` will be        //! done in order of ascending index. In other words, `f` will be        //! called as `f(0)`, `f(1)`, `f(2)`, etc., but with `integral_constant`s        //! instead of normal integers. Side effects can also be done in the        //! function passed to `times` and `times.with_index`.        template <typename F>        static constexpr void times(F&& f) {            f(); f(); ... f(); // n times total        }        //! Equivalent to `hana::plus`        template <typename X, typename Y>        friend constexpr auto operator+(X&& x, Y&& y);        //! Equivalent to `hana::minus`        template <typename X, typename Y>        friend constexpr auto operator-(X&& x, Y&& y);        //! Equivalent to `hana::negate`        template <typename X>        friend constexpr auto operator-(X&& x);        //! Equivalent to `hana::mult`        template <typename X, typename Y>        friend constexpr auto operator*(X&& x, Y&& y);        //! Equivalent to `hana::div`        template <typename X, typename Y>        friend constexpr auto operator/(X&& x, Y&& y);        //! Equivalent to `hana::mod`        template <typename X, typename Y>        friend constexpr auto operator%(X&& x, Y&& y);        //! Equivalent to `hana::equal`        template <typename X, typename Y>        friend constexpr auto operator==(X&& x, Y&& y);        //! Equivalent to `hana::not_equal`        template <typename X, typename Y>        friend constexpr auto operator!=(X&& x, Y&& y);        //! Equivalent to `hana::or_`        template <typename X, typename Y>        friend constexpr auto operator||(X&& x, Y&& y);        //! Equivalent to `hana::and_`        template <typename X, typename Y>        friend constexpr auto operator&&(X&& x, Y&& y);        //! Equivalent to `hana::not_`        template <typename X>        friend constexpr auto operator!(X&& x);        //! Equivalent to `hana::less`        template <typename X, typename Y>        friend constexpr auto operator<(X&& x, Y&& y);        //! Equivalent to `hana::greater`        template <typename X, typename Y>        friend constexpr auto operator>(X&& x, Y&& y);        //! Equivalent to `hana::less_equal`        template <typename X, typename Y>        friend constexpr auto operator<=(X&& x, Y&& y);        //! Equivalent to `hana::greater_equal`        template <typename X, typename Y>        friend constexpr auto operator>=(X&& x, Y&& y);    };#else    template <typename T, T v>#ifdef BOOST_HANA_WORKAROUND_MSVC_EMPTYBASE    struct __declspec(empty_bases) integral_constant#else    struct integral_constant#endif        : std::integral_constant<T, v>        , detail::operators::adl<integral_constant<T, v>>    {        using type = integral_constant; // override std::integral_constant::type        static constexpr ic_detail::times_t<T, v> times{};        using hana_tag = integral_constant_tag<T>;    };#endifBOOST_HANA_NAMESPACE_END#endif // !BOOST_HANA_DETAIL_INTEGRAL_CONSTANT_HPP
 |