diff --git a/example/core/default_instance.cpp b/example/core/default_instance.cpp index 75526f49f..aaac086a8 100644 --- a/example/core/default_instance.cpp +++ b/example/core/default_instance.cpp @@ -16,21 +16,19 @@ namespace hana = boost::hana; struct Showable { BOOST_HANA_TYPECLASS(Showable); struct mcd { }; + + template + struct default_instance : mcd { + template + static std::string show_impl(X) + { return ""; } + }; }; BOOST_HANA_CONSTEXPR_LAMBDA auto show = [](auto x) { return Showable::instance>::show_impl(x); }; -namespace boost { namespace hana { - template <> - struct default_instance : Showable::mcd { - template - static std::string show_impl(X) - { return ""; } - }; -}} - template <> struct Showable::instance : Showable::mcd { static auto show_impl(int i) diff --git a/include/boost/hana/detail/typeclasses.hpp b/include/boost/hana/detail/typeclasses.hpp index 737acb087..e7f53cfa2 100644 --- a/include/boost/hana/detail/typeclasses.hpp +++ b/include/boost/hana/detail/typeclasses.hpp @@ -11,9 +11,21 @@ Distributed under the Boost Software License, Version 1.0. #define BOOST_HANA_DETAIL_TYPECLASSES_HPP namespace boost { namespace hana { + struct disable; + namespace core_detail { - template - struct dependent { using type = x; }; + template + struct default_instance { + using type = disable; + }; + + template + struct default_instance< + decltype((void)(typename Typeclass::template default_instance*)0), + Typeclass, Args... + > { + using type = typename Typeclass::template default_instance; + }; } //! @ingroup core @@ -47,6 +59,31 @@ namespace boost { namespace hana { //! In all cases, the minimal complete definition(s) and the location of //! their associated set of provided methods are documented. //! + //! It is also possible to define a default instance for all data types. + //! To do so, provide a nested `default_instance` template inside the + //! type class: + //! @code + //! struct Typeclass { + //! BOOST_HANA_TYPECLASS(Typeclass); + //! template + //! struct default_instance { + //! // default instance for all data types + //! }; + //! }; + //! @endcode + //! + //! The nested `default_instance` should be just like a normal instance; + //! see below for how to instantiate a type class. This can be used to + //! provide a default behavior for all data types while still allowing + //! this behavior to be customized by instantiating the type class. However, + //! this should seldom be used because methods with a meaningful behavior + //! for all data types are rare. This feature is provided for flexibility, + //! but it should be a hint to reconsider your type class design if you + //! are about to use it. + //! + //! ### Example + //! @include example/core/default_instance.cpp + //! //! //! ### Instantiating a type class //! Instantiating a type class is done by specializing the associated @@ -124,11 +161,9 @@ namespace boost { namespace hana { \ template \ struct instance> \ - : ::boost::hana::default_instance< \ - typename ::boost::hana::core_detail::dependent< \ - NAME, ::boost::hana::when \ - >::type \ - > \ + : ::boost::hana::core_detail::default_instance< \ + void, NAME, T \ + >::type \ { } \ /** @endcond */ \ /**/ @@ -147,11 +182,9 @@ namespace boost { namespace hana { \ template \ struct instance> \ - : ::boost::hana::default_instance< \ - typename ::boost::hana::core_detail::dependent< \ - NAME, ::boost::hana::when \ - >::type \ - > \ + : ::boost::hana::core_detail::default_instance< \ + void, NAME, T, U \ + >::type \ { } \ /** @endcond */ \ /**/ @@ -186,32 +219,6 @@ namespace boost { namespace hana { //! @include example/core/disable.cpp struct disable { }; - //! @ingroup core - //! Defines a default instance for the given type class. - //! - //! To define a default instance for all data types, specialize the - //! `default_instance` template for the desired type class: - //! @code - //! template <> - //! struct default_instance { - //! // default instance for all data types - //! }; - //! @endcode - //! - //! `default_instance` should be just like a normal instance; see below - //! for how to instantiate a type class. This can be used to provide a - //! default behavior for all data types while still allowing this behavior - //! to be customized by instantiating the type class. However, this should - //! seldom be used because methods with a meaningful behavior for all - //! data types are rare. This feature is provided for flexibility, but - //! it should be a hint to reconsider your type class design if you are - //! about to use it. - //! - //! ### Example - //! @include example/core/default_instance.cpp - template - struct default_instance : disable { }; - namespace core_detail { template struct default_datatype { using type = T; }; diff --git a/test/core/typeclass_resolution.cpp b/test/core/typeclass_resolution.cpp index 5817f4254..2419245bd 100644 --- a/test/core/typeclass_resolution.cpp +++ b/test/core/typeclass_resolution.cpp @@ -22,19 +22,17 @@ struct partially_specialized_instance; template struct explicitly_specialized_instance; +template struct defaulted_instance; struct Typeclass { BOOST_HANA_TYPECLASS(Typeclass); -}; - -namespace boost { namespace hana { - template <> - struct default_instance< ::Typeclass> { - using which = defaulted_instance; + template + struct default_instance { + using which = defaulted_instance; }; -}} +}; template struct predicate { static constexpr bool value = false; }; @@ -137,7 +135,7 @@ static_assert(std::is_same< static_assert(std::is_same< Typeclass::instance::which, - defaulted_instance + defaulted_instance >::value, ""); int main() { } diff --git a/test/sandbox/logical.cpp b/test/sandbox/logical.cpp index 618a4f768..4bf7b4308 100644 --- a/test/sandbox/logical.cpp +++ b/test/sandbox/logical.cpp @@ -34,6 +34,8 @@ namespace hana = boost::hana; struct Logical { BOOST_HANA_TYPECLASS(Logical); struct mcd; + template + struct default_instance; }; BOOST_HANA_CONSTEXPR_LAMBDA auto if_ = [](auto logical, auto then_, auto else_) { @@ -78,20 +80,18 @@ struct Logical::mcd { { return eval_if(c, hana::always(t), hana::always(e)); } }; -namespace boost { namespace hana { - template <> - struct default_instance< ::Logical> : ::Logical::mcd { - template - static constexpr auto eval_if_impl(Cond c, Then t, Else e) { - auto would_recurse = hana::decltype_(::eval(c)) == hana::decltype_(c); - static_assert(!would_recurse(), - "Condition is probably not a logical. Trying to evaluate " - "it and use it as the condition to if_ again would cause " - "infinite recursion."); - return ::eval_if(::eval(c), t, e); - } - }; -}} +template +struct Logical::default_instance : Logical::mcd { + template + static constexpr auto eval_if_impl(Cond c, Then t, Else e) { + auto would_recurse = hana::decltype_(eval(c)) == hana::decltype_(c); + static_assert(!would_recurse(), + "Condition is probably not a logical. Trying to evaluate " + "it and use it as the condition to if_ again would cause " + "infinite recursion."); + return eval_if(eval(c), t, e); + } +}; template <> struct Logical::instance : Logical::mcd {