/*! @file Defines the barebones `boost::hana::integral_constant` template, but no operations on it. @copyright Louis Dionne 2013-2016 Distributed 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 #include #include BOOST_HANA_NAMESPACE_BEGIN //! Tag representing `hana::integral_constant`. //! @relates hana::integral_constant template struct integral_constant_tag { using value_type = T; }; namespace ic_detail { template struct with_index_t { template constexpr void operator()(F&& f) const; }; template struct times_t { static constexpr with_index_t with_index{}; template 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{} @ integral_constant{} == integral_constant{} //! @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::value == v // of type T //! @endcode //! The model of `Constant` follows naturally from the model of `IntegralConstant`, i.e. //! @code //! value>() == 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 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_::%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 static constexpr void times(F&& f) { f(); f(); ... f(); // n times total } //! Equivalent to `hana::plus` template friend constexpr auto operator+(X&& x, Y&& y); //! Equivalent to `hana::minus` template friend constexpr auto operator-(X&& x, Y&& y); //! Equivalent to `hana::negate` template friend constexpr auto operator-(X&& x); //! Equivalent to `hana::mult` template friend constexpr auto operator*(X&& x, Y&& y); //! Equivalent to `hana::div` template friend constexpr auto operator/(X&& x, Y&& y); //! Equivalent to `hana::mod` template friend constexpr auto operator%(X&& x, Y&& y); //! Equivalent to `hana::equal` template friend constexpr auto operator==(X&& x, Y&& y); //! Equivalent to `hana::not_equal` template friend constexpr auto operator!=(X&& x, Y&& y); //! Equivalent to `hana::or_` template friend constexpr auto operator||(X&& x, Y&& y); //! Equivalent to `hana::and_` template friend constexpr auto operator&&(X&& x, Y&& y); //! Equivalent to `hana::not_` template friend constexpr auto operator!(X&& x); //! Equivalent to `hana::less` template friend constexpr auto operator<(X&& x, Y&& y); //! Equivalent to `hana::greater` template friend constexpr auto operator>(X&& x, Y&& y); //! Equivalent to `hana::less_equal` template friend constexpr auto operator<=(X&& x, Y&& y); //! Equivalent to `hana::greater_equal` template friend constexpr auto operator>=(X&& x, Y&& y); }; #else template struct integral_constant : std::integral_constant , detail::operators::adl> { using type = integral_constant; // override std::integral_constant::type static constexpr ic_detail::times_t times{}; using hana_tag = integral_constant_tag; }; #endif BOOST_HANA_NAMESPACE_END #endif // !BOOST_HANA_DETAIL_INTEGRAL_CONSTANT_HPP