From fd9edff55994bca24e4b27af2027b34148879f8c Mon Sep 17 00:00:00 2001 From: Louis Dionne Date: Mon, 5 Mar 2018 13:42:33 -0800 Subject: [PATCH 01/13] [string] Add comment about BOOST_HANA_STRING not being constexpr pre-17 Closes #390 --- include/boost/hana/fwd/string.hpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/include/boost/hana/fwd/string.hpp b/include/boost/hana/fwd/string.hpp index 80c1622500..8f061e5cff 100644 --- a/include/boost/hana/fwd/string.hpp +++ b/include/boost/hana/fwd/string.hpp @@ -212,7 +212,8 @@ BOOST_HANA_NAMESPACE_BEGIN //! //! This macro is a more convenient alternative to `string_c` for creating //! compile-time strings. However, since this macro uses a lambda - //! internally, it can't be used in an unevaluated context. + //! internally, it can't be used in an unevaluated context, or where + //! a constant expression is expected before C++17. //! //! //! Example From 16a7bcda548fc8ed4d3c9d22b4581afc9dd4f2e3 Mon Sep 17 00:00:00 2001 From: Jason Rice Date: Fri, 6 Apr 2018 13:58:08 -0700 Subject: [PATCH 02/13] [lift] Defer concept check until invocation --- include/boost/hana/fwd/lift.hpp | 5 ++++- include/boost/hana/lift.hpp | 30 +++++++++++++++--------------- 2 files changed, 19 insertions(+), 16 deletions(-) diff --git a/include/boost/hana/fwd/lift.hpp b/include/boost/hana/fwd/lift.hpp index 9491dab8a4..2d4ac6cc13 100644 --- a/include/boost/hana/fwd/lift.hpp +++ b/include/boost/hana/fwd/lift.hpp @@ -49,7 +49,10 @@ BOOST_HANA_NAMESPACE_BEGIN struct lift_impl : lift_impl> { }; template - struct lift_t; + struct lift_t { + template + constexpr auto operator()(X&& x) const; + }; template constexpr lift_t lift{}; diff --git a/include/boost/hana/lift.hpp b/include/boost/hana/lift.hpp index b8ab3431c2..deb90ce002 100644 --- a/include/boost/hana/lift.hpp +++ b/include/boost/hana/lift.hpp @@ -20,22 +20,22 @@ Distributed under the Boost Software License, Version 1.0. BOOST_HANA_NAMESPACE_BEGIN + //! @cond template - struct lift_t { - #ifndef BOOST_HANA_CONFIG_DISABLE_CONCEPT_CHECKS - static_assert(hana::Applicative::value, - "hana::lift requires 'A' to be an Applicative"); - #endif - - template - constexpr auto operator()(X&& x) const { - using Lift = BOOST_HANA_DISPATCH_IF(lift_impl, - hana::Applicative::value - ); - - return Lift::apply(static_cast(x)); - } - }; + template + constexpr auto lift_t::operator()(X&& x) const { + #ifndef BOOST_HANA_CONFIG_DISABLE_CONCEPT_CHECKS + static_assert(hana::Applicative::value, + "hana::lift requires 'A' to be an Applicative"); + #endif + + using Lift = BOOST_HANA_DISPATCH_IF(lift_impl, + hana::Applicative::value + ); + + return Lift::apply(static_cast(x)); + } + //! @endcond template struct lift_impl> : default_ { From 7cd10e98bde41a2e197138cb423a6f983a66e645 Mon Sep 17 00:00:00 2001 From: Jason Rice Date: Wed, 11 Apr 2018 22:28:01 -0700 Subject: [PATCH 03/13] More deferring concept checks --- include/boost/hana/empty.hpp | 16 ++--- include/boost/hana/fwd/empty.hpp | 4 +- include/boost/hana/fwd/monadic_fold_left.hpp | 8 ++- include/boost/hana/fwd/monadic_fold_right.hpp | 8 ++- include/boost/hana/fwd/one.hpp | 4 +- include/boost/hana/fwd/product.hpp | 5 +- include/boost/hana/fwd/replicate.hpp | 5 +- include/boost/hana/fwd/sum.hpp | 5 +- include/boost/hana/fwd/tap.hpp | 5 +- include/boost/hana/fwd/zero.hpp | 4 +- include/boost/hana/lift.hpp | 8 +-- include/boost/hana/monadic_fold_left.hpp | 64 ++++++++++--------- include/boost/hana/monadic_fold_right.hpp | 64 ++++++++++--------- include/boost/hana/one.hpp | 16 ++--- include/boost/hana/product.hpp | 30 ++++----- include/boost/hana/replicate.hpp | 30 ++++----- include/boost/hana/sum.hpp | 30 ++++----- include/boost/hana/tap.hpp | 18 +++--- include/boost/hana/zero.hpp | 16 ++--- 19 files changed, 186 insertions(+), 154 deletions(-) diff --git a/include/boost/hana/empty.hpp b/include/boost/hana/empty.hpp index 8cb97a3ebc..86b81f408c 100644 --- a/include/boost/hana/empty.hpp +++ b/include/boost/hana/empty.hpp @@ -20,21 +20,21 @@ Distributed under the Boost Software License, Version 1.0. BOOST_HANA_NAMESPACE_BEGIN + //! @cond template - struct empty_t { + constexpr auto empty_t::operator()() const { #ifndef BOOST_HANA_CONFIG_DISABLE_CONCEPT_CHECKS static_assert(hana::MonadPlus::value, "hana::empty() requires 'M' to be a MonadPlus"); #endif - constexpr auto operator()() const { - using Empty = BOOST_HANA_DISPATCH_IF(empty_impl, - hana::MonadPlus::value - ); + using Empty = BOOST_HANA_DISPATCH_IF(empty_impl, + hana::MonadPlus::value + ); - return Empty::apply(); - } - }; + return Empty::apply(); + } + //! @endcond template struct empty_impl> : default_ { diff --git a/include/boost/hana/fwd/empty.hpp b/include/boost/hana/fwd/empty.hpp index ed3cc38cc7..719f58055f 100644 --- a/include/boost/hana/fwd/empty.hpp +++ b/include/boost/hana/fwd/empty.hpp @@ -41,7 +41,9 @@ BOOST_HANA_NAMESPACE_BEGIN struct empty_impl : empty_impl> { }; template - struct empty_t; + struct empty_t { + constexpr auto operator()() const; + }; template constexpr empty_t empty{}; diff --git a/include/boost/hana/fwd/monadic_fold_left.hpp b/include/boost/hana/fwd/monadic_fold_left.hpp index c037989dea..aa66097b3e 100644 --- a/include/boost/hana/fwd/monadic_fold_left.hpp +++ b/include/boost/hana/fwd/monadic_fold_left.hpp @@ -94,7 +94,13 @@ BOOST_HANA_NAMESPACE_BEGIN struct monadic_fold_left_impl : monadic_fold_left_impl> { }; template - struct monadic_fold_left_t; + struct monadic_fold_left_t { + template + constexpr decltype(auto) operator()(Xs&& xs, State&& state, F&& f) const; + + template + constexpr decltype(auto) operator()(Xs&& xs, F&& f) const; + }; template constexpr monadic_fold_left_t monadic_fold_left{}; diff --git a/include/boost/hana/fwd/monadic_fold_right.hpp b/include/boost/hana/fwd/monadic_fold_right.hpp index 2028e15369..fff6fc0c1f 100644 --- a/include/boost/hana/fwd/monadic_fold_right.hpp +++ b/include/boost/hana/fwd/monadic_fold_right.hpp @@ -96,7 +96,13 @@ BOOST_HANA_NAMESPACE_BEGIN struct monadic_fold_right_impl : monadic_fold_right_impl> { }; template - struct monadic_fold_right_t; + struct monadic_fold_right_t { + template + constexpr decltype(auto) operator()(Xs&& xs, State&& state, F&& f) const; + + template + constexpr decltype(auto) operator()(Xs&& xs, F&& f) const; + }; template constexpr monadic_fold_right_t monadic_fold_right{}; diff --git a/include/boost/hana/fwd/one.hpp b/include/boost/hana/fwd/one.hpp index d2c67b7228..27d4f37bd6 100644 --- a/include/boost/hana/fwd/one.hpp +++ b/include/boost/hana/fwd/one.hpp @@ -35,7 +35,9 @@ BOOST_HANA_NAMESPACE_BEGIN struct one_impl : one_impl> { }; template - struct one_t; + struct one_t { + constexpr decltype(auto) operator()() const; + }; template constexpr one_t one{}; diff --git a/include/boost/hana/fwd/product.hpp b/include/boost/hana/fwd/product.hpp index 96bbd77c4e..ff545ceacb 100644 --- a/include/boost/hana/fwd/product.hpp +++ b/include/boost/hana/fwd/product.hpp @@ -60,7 +60,10 @@ BOOST_HANA_NAMESPACE_BEGIN struct product_impl : product_impl> { }; template - struct product_t; + struct product_t { + template + constexpr decltype(auto) operator()(Xs&& xs) const; + }; template > constexpr product_t product{}; diff --git a/include/boost/hana/fwd/replicate.hpp b/include/boost/hana/fwd/replicate.hpp index 4861adabae..842812d692 100644 --- a/include/boost/hana/fwd/replicate.hpp +++ b/include/boost/hana/fwd/replicate.hpp @@ -65,7 +65,10 @@ BOOST_HANA_NAMESPACE_BEGIN struct replicate_impl : replicate_impl> { }; template - struct replicate_t; + struct replicate_t { + template + constexpr auto operator()(X&& x, N const& n) const; + }; template constexpr replicate_t replicate{}; diff --git a/include/boost/hana/fwd/sum.hpp b/include/boost/hana/fwd/sum.hpp index c565ecd7f7..6d7ee537b3 100644 --- a/include/boost/hana/fwd/sum.hpp +++ b/include/boost/hana/fwd/sum.hpp @@ -69,7 +69,10 @@ BOOST_HANA_NAMESPACE_BEGIN struct sum_impl : sum_impl> { }; template - struct sum_t; + struct sum_t { + template + constexpr decltype(auto) operator()(Xs&& xs) const; + }; template > constexpr sum_t sum{}; diff --git a/include/boost/hana/fwd/tap.hpp b/include/boost/hana/fwd/tap.hpp index 846c1d00e6..2f3809c1f3 100644 --- a/include/boost/hana/fwd/tap.hpp +++ b/include/boost/hana/fwd/tap.hpp @@ -55,7 +55,10 @@ BOOST_HANA_NAMESPACE_BEGIN struct tap_impl : tap_impl> { }; template - struct tap_t; + struct tap_t { + template + constexpr auto operator()(F&& f) const; + }; template constexpr tap_t tap{}; diff --git a/include/boost/hana/fwd/zero.hpp b/include/boost/hana/fwd/zero.hpp index 412614786d..fcbcfcc372 100644 --- a/include/boost/hana/fwd/zero.hpp +++ b/include/boost/hana/fwd/zero.hpp @@ -35,7 +35,9 @@ BOOST_HANA_NAMESPACE_BEGIN struct zero_impl : zero_impl> { }; template - struct zero_t; + struct zero_t { + constexpr decltype(auto) operator()() const; + }; template constexpr zero_t zero{}; diff --git a/include/boost/hana/lift.hpp b/include/boost/hana/lift.hpp index deb90ce002..c1d7803788 100644 --- a/include/boost/hana/lift.hpp +++ b/include/boost/hana/lift.hpp @@ -24,10 +24,10 @@ BOOST_HANA_NAMESPACE_BEGIN template template constexpr auto lift_t::operator()(X&& x) const { - #ifndef BOOST_HANA_CONFIG_DISABLE_CONCEPT_CHECKS - static_assert(hana::Applicative::value, - "hana::lift requires 'A' to be an Applicative"); - #endif + #ifndef BOOST_HANA_CONFIG_DISABLE_CONCEPT_CHECKS + static_assert(hana::Applicative::value, + "hana::lift requires 'A' to be an Applicative"); + #endif using Lift = BOOST_HANA_DISPATCH_IF(lift_impl, hana::Applicative::value diff --git a/include/boost/hana/monadic_fold_left.hpp b/include/boost/hana/monadic_fold_left.hpp index e06c405604..3a1e8142a7 100644 --- a/include/boost/hana/monadic_fold_left.hpp +++ b/include/boost/hana/monadic_fold_left.hpp @@ -27,46 +27,50 @@ Distributed under the Boost Software License, Version 1.0. BOOST_HANA_NAMESPACE_BEGIN + //! @cond template - struct monadic_fold_left_t { + template + constexpr decltype(auto) monadic_fold_left_t::operator()(Xs&& xs, State&& state, F&& f) const { + using S = typename hana::tag_of::type; + using MonadicFoldLeft = BOOST_HANA_DISPATCH_IF(monadic_fold_left_impl, + hana::Foldable::value + ); + #ifndef BOOST_HANA_CONFIG_DISABLE_CONCEPT_CHECKS static_assert(hana::Monad::value, "hana::monadic_fold_left requires 'M' to be a Monad"); - #endif - template - constexpr decltype(auto) operator()(Xs&& xs, State&& state, F&& f) const { - using S = typename hana::tag_of::type; - using MonadicFoldLeft = BOOST_HANA_DISPATCH_IF(monadic_fold_left_impl, - hana::Foldable::value - ); + static_assert(hana::Foldable::value, + "hana::monadic_fold_left(xs, state, f) requires 'xs' to be Foldable"); + #endif - #ifndef BOOST_HANA_CONFIG_DISABLE_CONCEPT_CHECKS - static_assert(hana::Foldable::value, - "hana::monadic_fold_left(xs, state, f) requires 'xs' to be Foldable"); - #endif + return MonadicFoldLeft::template apply(static_cast(xs), + static_cast(state), + static_cast(f)); + } + //! @endcond - return MonadicFoldLeft::template apply(static_cast(xs), - static_cast(state), - static_cast(f)); - } + //! @cond + template + template + constexpr decltype(auto) monadic_fold_left_t::operator()(Xs&& xs, F&& f) const { + using S = typename hana::tag_of::type; + using MonadicFoldLeft = BOOST_HANA_DISPATCH_IF(monadic_fold_left_impl, + hana::Foldable::value + ); - template - constexpr decltype(auto) operator()(Xs&& xs, F&& f) const { - using S = typename hana::tag_of::type; - using MonadicFoldLeft = BOOST_HANA_DISPATCH_IF(monadic_fold_left_impl, - hana::Foldable::value - ); + #ifndef BOOST_HANA_CONFIG_DISABLE_CONCEPT_CHECKS + static_assert(hana::Monad::value, + "hana::monadic_fold_left requires 'M' to be a Monad"); - #ifndef BOOST_HANA_CONFIG_DISABLE_CONCEPT_CHECKS - static_assert(hana::Foldable::value, - "hana::monadic_fold_left(xs, f) requires 'xs' to be Foldable"); - #endif + static_assert(hana::Foldable::value, + "hana::monadic_fold_left(xs, f) requires 'xs' to be Foldable"); + #endif - return MonadicFoldLeft::template apply(static_cast(xs), - static_cast(f)); - } - }; + return MonadicFoldLeft::template apply(static_cast(xs), + static_cast(f)); + } + //! @endcond namespace detail { struct foldlM_helper { diff --git a/include/boost/hana/monadic_fold_right.hpp b/include/boost/hana/monadic_fold_right.hpp index 7026b058c3..c822d1d003 100644 --- a/include/boost/hana/monadic_fold_right.hpp +++ b/include/boost/hana/monadic_fold_right.hpp @@ -27,45 +27,49 @@ Distributed under the Boost Software License, Version 1.0. BOOST_HANA_NAMESPACE_BEGIN + //! @cond template - struct monadic_fold_right_t { + template + constexpr decltype(auto) monadic_fold_right_t::operator()(Xs&& xs, State&& state, F&& f) const { + using S = typename hana::tag_of::type; + using MonadicFoldRight = BOOST_HANA_DISPATCH_IF(monadic_fold_right_impl, + hana::Foldable::value + ); + #ifndef BOOST_HANA_CONFIG_DISABLE_CONCEPT_CHECKS static_assert(hana::Monad::value, "hana::monadic_fold_right requires 'M' to be a Monad"); - #endif - template - constexpr decltype(auto) operator()(Xs&& xs, State&& state, F&& f) const { - using S = typename hana::tag_of::type; - using MonadicFoldRight = BOOST_HANA_DISPATCH_IF(monadic_fold_right_impl, - hana::Foldable::value - ); + static_assert(hana::Foldable::value, + "hana::monadic_fold_right(xs, state, f) requires 'xs' to be Foldable"); + #endif - #ifndef BOOST_HANA_CONFIG_DISABLE_CONCEPT_CHECKS - static_assert(hana::Foldable::value, - "hana::monadic_fold_right(xs, state, f) requires 'xs' to be Foldable"); - #endif + return MonadicFoldRight::template apply(static_cast(xs), + static_cast(state), + static_cast(f)); + } + //! @endcond - return MonadicFoldRight::template apply(static_cast(xs), - static_cast(state), - static_cast(f)); - } + //! @cond + template + template + constexpr decltype(auto) monadic_fold_right_t::operator()(Xs&& xs, F&& f) const { + using S = typename hana::tag_of::type; + using MonadicFoldRight = BOOST_HANA_DISPATCH_IF(monadic_fold_right_impl, + hana::Foldable::value + ); - template - constexpr decltype(auto) operator()(Xs&& xs, F&& f) const { - using S = typename hana::tag_of::type; - using MonadicFoldRight = BOOST_HANA_DISPATCH_IF(monadic_fold_right_impl, - hana::Foldable::value - ); + #ifndef BOOST_HANA_CONFIG_DISABLE_CONCEPT_CHECKS + static_assert(hana::Monad::value, + "hana::monadic_fold_right requires 'M' to be a Monad"); - #ifndef BOOST_HANA_CONFIG_DISABLE_CONCEPT_CHECKS - static_assert(hana::Foldable::value, - "hana::monadic_fold_right(xs, f) requires 'xs' to be Foldable"); - #endif - return MonadicFoldRight::template apply(static_cast(xs), - static_cast(f)); - } - }; + static_assert(hana::Foldable::value, + "hana::monadic_fold_right(xs, f) requires 'xs' to be Foldable"); + #endif + return MonadicFoldRight::template apply(static_cast(xs), + static_cast(f)); + } + //! @endcond namespace detail { struct foldrM_helper { diff --git a/include/boost/hana/one.hpp b/include/boost/hana/one.hpp index b8d759b8c0..df27b1e834 100644 --- a/include/boost/hana/one.hpp +++ b/include/boost/hana/one.hpp @@ -23,21 +23,21 @@ Distributed under the Boost Software License, Version 1.0. BOOST_HANA_NAMESPACE_BEGIN + //! @cond template - struct one_t { + constexpr decltype(auto) one_t::operator()() const { #ifndef BOOST_HANA_CONFIG_DISABLE_CONCEPT_CHECKS static_assert(hana::Ring::value, "hana::one() requires 'R' to be a Ring"); #endif - constexpr decltype(auto) operator()() const { - using One = BOOST_HANA_DISPATCH_IF(one_impl, - hana::Ring::value - ); + using One = BOOST_HANA_DISPATCH_IF(one_impl, + hana::Ring::value + ); - return One::apply(); - } - }; + return One::apply(); + } + //! @endcond template struct one_impl> : default_ { diff --git a/include/boost/hana/product.hpp b/include/boost/hana/product.hpp index 8d3bad9fc3..a419b15b40 100644 --- a/include/boost/hana/product.hpp +++ b/include/boost/hana/product.hpp @@ -23,28 +23,26 @@ Distributed under the Boost Software License, Version 1.0. BOOST_HANA_NAMESPACE_BEGIN + //! @cond template - struct product_t { + template + constexpr decltype(auto) product_t::operator()(Xs&& xs) const { + using S = typename hana::tag_of::type; + using Product = BOOST_HANA_DISPATCH_IF(product_impl, + hana::Foldable::value + ); + #ifndef BOOST_HANA_CONFIG_DISABLE_CONCEPT_CHECKS static_assert(hana::Ring::value, "hana::product requires 'R' to be a Ring"); - #endif - - template - constexpr decltype(auto) operator()(Xs&& xs) const { - using S = typename hana::tag_of::type; - using Product = BOOST_HANA_DISPATCH_IF(product_impl, - hana::Foldable::value - ); - #ifndef BOOST_HANA_CONFIG_DISABLE_CONCEPT_CHECKS - static_assert(hana::Foldable::value, - "hana::product(xs) requires 'xs' to be Foldable"); - #endif + static_assert(hana::Foldable::value, + "hana::product(xs) requires 'xs' to be Foldable"); + #endif - return Product::template apply(static_cast(xs)); - } - }; + return Product::template apply(static_cast(xs)); + } + //! @endcond template struct product_impl> : default_ { diff --git a/include/boost/hana/replicate.hpp b/include/boost/hana/replicate.hpp index f04c4d8a44..3d82712d4f 100644 --- a/include/boost/hana/replicate.hpp +++ b/include/boost/hana/replicate.hpp @@ -25,28 +25,26 @@ Distributed under the Boost Software License, Version 1.0. BOOST_HANA_NAMESPACE_BEGIN + //! @cond template - struct replicate_t { + template + constexpr auto replicate_t::operator()(X&& x, N const& n) const { + using Replicate = BOOST_HANA_DISPATCH_IF(replicate_impl, + hana::MonadPlus::value && + hana::IntegralConstant::value + ); + #ifndef BOOST_HANA_CONFIG_DISABLE_CONCEPT_CHECKS static_assert(hana::MonadPlus::value, "hana::replicate(x, n) requires 'M' to be a MonadPlus"); - #endif - - template - constexpr auto operator()(X&& x, N const& n) const { - using Replicate = BOOST_HANA_DISPATCH_IF(replicate_impl, - hana::MonadPlus::value && - hana::IntegralConstant::value - ); - #ifndef BOOST_HANA_CONFIG_DISABLE_CONCEPT_CHECKS - static_assert(hana::IntegralConstant::value, - "hana::replicate(x, n) requires 'n' to be an IntegralConstant"); - #endif + static_assert(hana::IntegralConstant::value, + "hana::replicate(x, n) requires 'n' to be an IntegralConstant"); + #endif - return Replicate::apply(static_cast(x), n); - } - }; + return Replicate::apply(static_cast(x), n); + } + //! @endcond template struct replicate_impl> : default_ { diff --git a/include/boost/hana/sum.hpp b/include/boost/hana/sum.hpp index 5c86dafdde..2b6f6b8219 100644 --- a/include/boost/hana/sum.hpp +++ b/include/boost/hana/sum.hpp @@ -23,28 +23,26 @@ Distributed under the Boost Software License, Version 1.0. BOOST_HANA_NAMESPACE_BEGIN + //! @cond template - struct sum_t { + template + constexpr decltype(auto) sum_t::operator()(Xs&& xs) const { + using S = typename hana::tag_of::type; + using Sum = BOOST_HANA_DISPATCH_IF(sum_impl, + hana::Foldable::value + ); + #ifndef BOOST_HANA_CONFIG_DISABLE_CONCEPT_CHECKS static_assert(hana::Monoid::value, "hana::sum requires 'M' to be a Monoid"); - #endif - - template - constexpr decltype(auto) operator()(Xs&& xs) const { - using S = typename hana::tag_of::type; - using Sum = BOOST_HANA_DISPATCH_IF(sum_impl, - hana::Foldable::value - ); - #ifndef BOOST_HANA_CONFIG_DISABLE_CONCEPT_CHECKS - static_assert(hana::Foldable::value, - "hana::sum(xs) requires 'xs' to be Foldable"); - #endif + static_assert(hana::Foldable::value, + "hana::sum(xs) requires 'xs' to be Foldable"); + #endif - return Sum::template apply(static_cast(xs)); - } - }; + return Sum::template apply(static_cast(xs)); + } + //! @endcond template struct sum_impl> : default_ { diff --git a/include/boost/hana/tap.hpp b/include/boost/hana/tap.hpp index 7d37318255..332f9ff83d 100644 --- a/include/boost/hana/tap.hpp +++ b/include/boost/hana/tap.hpp @@ -20,22 +20,22 @@ Distributed under the Boost Software License, Version 1.0. BOOST_HANA_NAMESPACE_BEGIN + //! @cond template - struct tap_t { + template + constexpr auto tap_t::operator()(F&& f) const { #ifndef BOOST_HANA_CONFIG_DISABLE_CONCEPT_CHECKS static_assert(hana::Monad::value, "hana::tap requires 'M' to be a Monad"); #endif - template - constexpr auto operator()(F&& f) const { - using Tap = BOOST_HANA_DISPATCH_IF(tap_impl, - hana::Monad::value - ); + using Tap = BOOST_HANA_DISPATCH_IF(tap_impl, + hana::Monad::value + ); - return Tap::apply(static_cast(f)); - } - }; + return Tap::apply(static_cast(f)); + } + //! @endcond namespace detail { template diff --git a/include/boost/hana/zero.hpp b/include/boost/hana/zero.hpp index baba9691f6..317023a1b3 100644 --- a/include/boost/hana/zero.hpp +++ b/include/boost/hana/zero.hpp @@ -23,21 +23,21 @@ Distributed under the Boost Software License, Version 1.0. BOOST_HANA_NAMESPACE_BEGIN + //! @cond template - struct zero_t { + constexpr decltype(auto) zero_t::operator()() const { #ifndef BOOST_HANA_CONFIG_DISABLE_CONCEPT_CHECKS static_assert(hana::Monoid::value, "hana::zero() requires 'M' to be a Monoid"); #endif - constexpr decltype(auto) operator()() const { - using Zero = BOOST_HANA_DISPATCH_IF(zero_impl, - hana::Monoid::value - ); + using Zero = BOOST_HANA_DISPATCH_IF(zero_impl, + hana::Monoid::value + ); - return Zero::apply(); - } - }; + return Zero::apply(); + } + //! @endcond template struct zero_impl> : default_ { From 5af6066e616a2069bbf80cf687ccfe2c6e7b2530 Mon Sep 17 00:00:00 2001 From: Louis Dionne Date: Sat, 3 Mar 2018 12:26:06 -0800 Subject: [PATCH 04/13] Make some containers final and add notes about assumptions about representation Also, add tests to make sure that an empty pair can be EBO'd. This one is very important because a typical use case is to create a tuple of pairs of empty types (e.g. in hana::map), and we expect this to be empty. --- doc/tutorial.hpp | 5 ++++- include/boost/hana/fwd/basic_tuple.hpp | 5 +++++ include/boost/hana/fwd/map.hpp | 8 +++++--- include/boost/hana/fwd/optional.hpp | 5 +++++ include/boost/hana/fwd/pair.hpp | 5 +++++ include/boost/hana/fwd/range.hpp | 3 ++- include/boost/hana/fwd/set.hpp | 3 ++- include/boost/hana/fwd/string.hpp | 3 ++- include/boost/hana/fwd/tuple.hpp | 5 +++++ include/boost/hana/map.hpp | 2 +- include/boost/hana/set.hpp | 2 +- include/boost/hana/tuple.hpp | 4 ++-- test/pair/empty_storage.cpp | 21 ++++++++++++++++----- test/tuple/empty_member.cpp | 10 +++++----- 14 files changed, 60 insertions(+), 21 deletions(-) diff --git a/doc/tutorial.hpp b/doc/tutorial.hpp index 0b546390e4..6b70351747 100644 --- a/doc/tutorial.hpp +++ b/doc/tutorial.hpp @@ -2024,7 +2024,10 @@ a container unspecified; they are explained in the [rationales](@ref tutorial-rationales-container_representation). When the representation of a container is implementation-defined, one must be careful not to make any assumptions about it, unless those assumption -are explicitly allowed in the documentation of the container. +are explicitly allowed in the documentation of the container. For example, +assuming that one can safely inherit from a container or that the elements +in the container are stored in the same order as specified in its template +argument list is generally not safe. @subsubsection tutorial-containers-types-overloading Overloading on container types diff --git a/include/boost/hana/fwd/basic_tuple.hpp b/include/boost/hana/fwd/basic_tuple.hpp index 8444f0f50e..69d4073f03 100644 --- a/include/boost/hana/fwd/basic_tuple.hpp +++ b/include/boost/hana/fwd/basic_tuple.hpp @@ -22,6 +22,11 @@ BOOST_HANA_NAMESPACE_BEGIN //! `std::tuple`, `basic_tuple` provides the strict minimum required to //! implement a closure with maximum compile-time efficiency. //! + //! @note + //! When you use a container, remember not to make assumptions about its + //! representation, unless the documentation gives you those guarantees. + //! More details [in the tutorial](@ref tutorial-containers-types). + //! //! //! Modeled concepts //! ---------------- diff --git a/include/boost/hana/fwd/map.hpp b/include/boost/hana/fwd/map.hpp index c00f57195f..782b0f1e97 100644 --- a/include/boost/hana/fwd/map.hpp +++ b/include/boost/hana/fwd/map.hpp @@ -36,21 +36,23 @@ BOOST_HANA_NAMESPACE_BEGIN //! keys must be `Hashable`, and any two keys with equal hashes must be //! `Comparable` with each other at compile-time. //! - //! Note that the actual representation of a `hana::map` is an implementation + //! @note + //! The actual representation of a `hana::map` is an implementation //! detail. As such, one should not assume anything more than what is //! explicitly documented as being part of the interface of a map, //! such as: //! - the presence of additional constructors //! - the presence of additional assignment operators //! - the fact that `hana::map` is, or is not, a dependent type - //! + //! . //! In particular, the last point is very important; `hana::map` //! is basically equivalent to //! @code //! decltype(hana::make_pair(std::declval()...)) //! @endcode //! which is not something that can be pattern-matched on during template - //! argument deduction, for example. + //! argument deduction, for example. More details [in the tutorial] + //! (@ref tutorial-containers-types). //! //! //! Modeled concepts diff --git a/include/boost/hana/fwd/optional.hpp b/include/boost/hana/fwd/optional.hpp index 28bb68e8af..8a348a8b12 100644 --- a/include/boost/hana/fwd/optional.hpp +++ b/include/boost/hana/fwd/optional.hpp @@ -38,6 +38,11 @@ BOOST_HANA_NAMESPACE_BEGIN //! by the compiler. This makes `hana::optional` well suited for static //! metaprogramming tasks, but very poor for anything dynamic. //! + //! @note + //! When you use a container, remember not to make assumptions about its + //! representation, unless the documentation gives you those guarantees. + //! More details [in the tutorial](@ref tutorial-containers-types). + //! //! //! Interoperation with `type`s //! --------------------------- diff --git a/include/boost/hana/fwd/pair.hpp b/include/boost/hana/fwd/pair.hpp index 897e87ad12..1ce0e22772 100644 --- a/include/boost/hana/fwd/pair.hpp +++ b/include/boost/hana/fwd/pair.hpp @@ -24,6 +24,11 @@ BOOST_HANA_NAMESPACE_BEGIN //! Instead, one must use the `hana::first` and `hana::second` free //! functions to access the elements of a pair. //! + //! @note + //! When you use a container, remember not to make assumptions about its + //! representation, unless the documentation gives you those guarantees. + //! More details [in the tutorial](@ref tutorial-containers-types). + //! //! //! Modeled concepts //! ---------------- diff --git a/include/boost/hana/fwd/range.hpp b/include/boost/hana/fwd/range.hpp index 82d0f75232..3fb2a939dc 100644 --- a/include/boost/hana/fwd/range.hpp +++ b/include/boost/hana/fwd/range.hpp @@ -35,7 +35,8 @@ BOOST_HANA_NAMESPACE_BEGIN //! The representation of `hana::range` is implementation defined. In //! particular, one should not take for granted the number and types //! of template parameters. The proper way to create a `hana::range` - //! is to use `hana::range_c` or `hana::make_range`. + //! is to use `hana::range_c` or `hana::make_range`. More details + //! [in the tutorial](@ref tutorial-containers-types). //! //! //! Modeled concepts diff --git a/include/boost/hana/fwd/set.hpp b/include/boost/hana/fwd/set.hpp index 7312854782..acbcbc7fb5 100644 --- a/include/boost/hana/fwd/set.hpp +++ b/include/boost/hana/fwd/set.hpp @@ -30,7 +30,8 @@ BOOST_HANA_NAMESPACE_BEGIN //! In particular, one should not take for granted the order of the //! template parameters and the presence of any additional constructors //! or assignment operators than what is documented. The canonical way of - //! creating a `hana::set` is through `hana::make_set`. + //! creating a `hana::set` is through `hana::make_set`. More details + //! [in the tutorial](@ref tutorial-containers-types). //! //! //! Modeled concepts diff --git a/include/boost/hana/fwd/string.hpp b/include/boost/hana/fwd/string.hpp index 8f061e5cff..8af2e709ba 100644 --- a/include/boost/hana/fwd/string.hpp +++ b/include/boost/hana/fwd/string.hpp @@ -40,7 +40,8 @@ BOOST_HANA_NAMESPACE_BEGIN //! In particular, one should not take for granted that the template //! parameters are `char`s. The proper way to access the contents of //! a `hana::string` as character constants is to use `hana::unpack`, - //! `.c_str()` or `hana::to`, as documented below. + //! `.c_str()` or `hana::to`, as documented below. More + //! details [in the tutorial](@ref tutorial-containers-types). //! //! //! Modeled concepts diff --git a/include/boost/hana/fwd/tuple.hpp b/include/boost/hana/fwd/tuple.hpp index f51ab9ac22..9ee2e00ace 100644 --- a/include/boost/hana/fwd/tuple.hpp +++ b/include/boost/hana/fwd/tuple.hpp @@ -32,6 +32,11 @@ BOOST_HANA_NAMESPACE_BEGIN //! sequence with a key-based access, then you should consider //! `hana::map` or `hana::set` instead. //! + //! @note + //! When you use a container, remember not to make assumptions about its + //! representation, unless the documentation gives you those guarantees. + //! More details [in the tutorial](@ref tutorial-containers-types). + //! //! //! Modeled concepts //! ---------------- diff --git a/include/boost/hana/map.hpp b/include/boost/hana/map.hpp index 8da5012190..7356208bc6 100644 --- a/include/boost/hana/map.hpp +++ b/include/boost/hana/map.hpp @@ -124,7 +124,7 @@ BOOST_HANA_NAMESPACE_BEGIN }; template - struct map_impl + struct map_impl final : detail::searchable_operators> , detail::operators::adl> { diff --git a/include/boost/hana/set.hpp b/include/boost/hana/set.hpp index 58979ed47f..53b4e8ec74 100644 --- a/include/boost/hana/set.hpp +++ b/include/boost/hana/set.hpp @@ -56,7 +56,7 @@ BOOST_HANA_NAMESPACE_BEGIN ////////////////////////////////////////////////////////////////////////// //! @cond template - struct set + struct set final : detail::operators::adl> , detail::searchable_operators> { diff --git a/include/boost/hana/tuple.hpp b/include/boost/hana/tuple.hpp index 3354a84bee..ae3cba819d 100644 --- a/include/boost/hana/tuple.hpp +++ b/include/boost/hana/tuple.hpp @@ -75,7 +75,7 @@ BOOST_HANA_NAMESPACE_BEGIN // tuple ////////////////////////////////////////////////////////////////////////// template <> - struct tuple<> + struct tuple<> final : detail::operators::adl> , detail::iterable_operators> { @@ -84,7 +84,7 @@ BOOST_HANA_NAMESPACE_BEGIN }; template - struct tuple + struct tuple final : detail::operators::adl> , detail::iterable_operators> { diff --git a/test/pair/empty_storage.cpp b/test/pair/empty_storage.cpp index cdea66cb99..0000414856 100644 --- a/test/pair/empty_storage.cpp +++ b/test/pair/empty_storage.cpp @@ -8,16 +8,27 @@ namespace hana = boost::hana; +struct empty1 { }; +struct empty2 { }; +struct empty3 { }; +struct empty4 { }; + // Make sure the storage of a pair is compressed -struct empty { }; -static_assert(sizeof(hana::pair) == sizeof(int), ""); -static_assert(sizeof(hana::pair) == sizeof(int), ""); +static_assert(sizeof(hana::pair) == sizeof(int), ""); +static_assert(sizeof(hana::pair) == sizeof(int), ""); // Also make sure that a pair with only empty members is empty too. This is // important to ensure, for example, that a tuple of pairs of empty objects // will get the EBO. -struct empty1 { }; -struct empty2 { }; static_assert(std::is_empty>{}, ""); +// Make sure that a pair of empty pairs is still empty. +static_assert(std::is_empty< + hana::pair, empty3> +>{}, ""); + +static_assert(std::is_empty< + hana::pair, hana::pair> +>{}, ""); + int main() { } diff --git a/test/tuple/empty_member.cpp b/test/tuple/empty_member.cpp index 34fc623de7..1bab831852 100644 --- a/test/tuple/empty_member.cpp +++ b/test/tuple/empty_member.cpp @@ -12,22 +12,22 @@ struct B { }; int main() { { using T = hana::tuple; - static_assert((sizeof(T) == sizeof(int)), ""); + static_assert(sizeof(T) == sizeof(int), ""); } { using T = hana::tuple; - static_assert((sizeof(T) == sizeof(int)), ""); + static_assert(sizeof(T) == sizeof(int), ""); } { using T = hana::tuple; - static_assert((sizeof(T) == sizeof(int)), ""); + static_assert(sizeof(T) == sizeof(int), ""); } { using T = hana::tuple; - static_assert((sizeof(T) == sizeof(int)), ""); + static_assert(sizeof(T) == sizeof(int), ""); } { using T = hana::tuple; - static_assert((sizeof(T) == sizeof(int)), ""); + static_assert(sizeof(T) == sizeof(int), ""); } } From 5df3603f1b50a800c0cee8a25081de7918abdd1d Mon Sep 17 00:00:00 2001 From: Jason Rice Date: Mon, 30 Apr 2018 09:03:14 -0700 Subject: [PATCH 05/13] [tuple] remove superfluous conversion in example --- example/tuple/tuple_c.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/example/tuple/tuple_c.cpp b/example/tuple/tuple_c.cpp index 8da09554cb..012221745b 100644 --- a/example/tuple/tuple_c.cpp +++ b/example/tuple/tuple_c.cpp @@ -13,7 +13,7 @@ namespace hana = boost::hana; int main() { BOOST_HANA_CONSTANT_CHECK( - hana::to_tuple(hana::tuple_c) + hana::tuple_c == hana::make_tuple(hana::int_c<0>, hana::int_c<1>, hana::int_c<2>) ); From ffba8a999067b6adac220b25ad358225646b25bc Mon Sep 17 00:00:00 2001 From: Louis Dionne Date: Tue, 29 May 2018 20:34:24 -0700 Subject: [PATCH 06/13] [ext.mpl] Support MPL sequences without BOOST_MPL_CFG_TYPEOF_BASED_SEQUENCES Fixes #399 --- include/boost/hana/ext/boost/mpl/vector.hpp | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/include/boost/hana/ext/boost/mpl/vector.hpp b/include/boost/hana/ext/boost/mpl/vector.hpp index 29e9972b5d..706c2dd06d 100644 --- a/include/boost/hana/ext/boost/mpl/vector.hpp +++ b/include/boost/hana/ext/boost/mpl/vector.hpp @@ -99,9 +99,25 @@ BOOST_HANA_NAMESPACE_BEGIN using vector_tag = ::boost::mpl::sequence_tag< ::boost::mpl::vector<>>::type; }}} + namespace mpl_detail { + // When `BOOST_MPL_CFG_TYPEOF_BASED_SEQUENCES` is not defined (e.g. on + // MSVC), different MPL sequences (like vector0 and vector1) have different + // tags, so we need to take that into account when we compare them. +#ifndef BOOST_MPL_CFG_TYPEOF_BASED_SEQUENCES + template + struct is_same_mpl_vector_tag : std::false_type { }; + + template