diff --git a/doc/tutorial.hpp b/doc/tutorial.hpp index 0b546390e4..c5e99b41ee 100644 --- a/doc/tutorial.hpp +++ b/doc/tutorial.hpp @@ -1703,7 +1703,7 @@ that type and cast it to `void`, for the same reason as we did for non-static members. -@subsubsection tutorial-introspection-is_valid-typename Nested type names +@subsubsection tutorial-introspection-is_valid-nested-typename Nested type names Checking for a nested type name is not hard, but it is slightly more convoluted than the previous cases: @@ -1716,7 +1716,7 @@ support types that can't be returned from functions, like array types or incomplete types. -@subsubsection tutorial-introspection-is_valid-template Nested templates +@subsubsection tutorial-introspection-is_valid-nested-template Nested templates Checking for a nested template name is similar to checking for a nested type name, except we use the `template_<...>` variable template instead of @@ -1725,6 +1725,21 @@ name, except we use the `template_<...>` variable template instead of @snippet example/tutorial/introspection.cpp nested_template +@subsubsection tutorial-introspection-is_valid-template Template specializations + +Checking whether a template specialization is valid can be done too, but we +now pass a `template_<...>` to `is_valid` instead of a `type<...>`, because +that's what we want to make the check on: + +@snippet example/tutorial/introspection.cpp template_specialization + +@note +Doing this will not cause the template to be instantiated. Hence, it will only +check whether the given template can be mentioned with the provided template +arguments, not whether the instantiation of the template with those arguments +is valid. Generally speaking, there is no way to check that programmatically. + + @subsection tutorial-introspection-sfinae Taking control of SFINAE Doing something only if an expression is well-formed is a very common pattern @@ -2024,7 +2039,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 @@ -2817,9 +2835,12 @@ very useful for porting existing code from e.g. Fusion/MPL to Hana: @snippet example/tutorial/ext/fusion_to_hana.cpp main @note -At this time, only adapters to use data types from other libraries inside Hana -are provided; adapters for the other way around (using Hana containers inside -other libraries) are not provided. +- At this time, only adapters to use data types from other libraries inside Hana + are provided; adapters for the other way around (using Hana containers inside + other libraries) are not provided. + +- The Fusion and MPL adapters are only guaranteed to work on the version of + Boost matching the version of Hana being used. However, using external adapters has a couple of pitfalls. For example, after a while using Hana, you might become used to comparing Hana tuples using the diff --git a/example/map/difference.cpp b/example/map/difference.cpp index 86bce0bc49..6b94b0a224 100644 --- a/example/map/difference.cpp +++ b/example/map/difference.cpp @@ -10,24 +10,23 @@ #include namespace hana = boost::hana; -using namespace hana::literals; -constexpr auto m1 = hana::make_map( - hana::make_pair("key1"_s, hana::type_c), - hana::make_pair("key2"_s, hana::type_c) +static auto m1 = hana::make_map( + hana::make_pair(BOOST_HANA_STRING("key1"), hana::type_c), + hana::make_pair(BOOST_HANA_STRING("key2"), hana::type_c) ); -constexpr auto m2 = hana::make_map( - hana::make_pair("key3"_s, hana::type_c), - hana::make_pair("key4"_s, hana::type_c), - hana::make_pair("key5"_s, hana::type_c) +static auto m2 = hana::make_map( + hana::make_pair(BOOST_HANA_STRING("key3"), hana::type_c), + hana::make_pair(BOOST_HANA_STRING("key4"), hana::type_c), + hana::make_pair(BOOST_HANA_STRING("key5"), hana::type_c) ); -constexpr auto m3 = hana::make_map( - hana::make_pair("key1"_s, hana::type_c), - hana::make_pair("key4"_s, hana::type_c), - hana::make_pair("key2"_s, hana::type_c) +static auto m3 = hana::make_map( + hana::make_pair(BOOST_HANA_STRING("key1"), hana::type_c), + hana::make_pair(BOOST_HANA_STRING("key4"), hana::type_c), + hana::make_pair(BOOST_HANA_STRING("key2"), hana::type_c) ); int main() { @@ -36,11 +35,11 @@ int main() { BOOST_HANA_CONSTANT_CHECK(hana::difference(m1, m3) == hana::make_map()); BOOST_HANA_CONSTANT_CHECK(hana::difference(m3, m1) == hana::make_map( - hana::make_pair("key4"_s, hana::type_c) + hana::make_pair(BOOST_HANA_STRING("key4"), hana::type_c) )); BOOST_HANA_CONSTANT_CHECK(hana::difference(m2, m3) == hana::make_map( - hana::make_pair("key3"_s, hana::type_c), - hana::make_pair("key5"_s, hana::type_c) + hana::make_pair(BOOST_HANA_STRING("key3"), hana::type_c), + hana::make_pair(BOOST_HANA_STRING("key5"), hana::type_c) )); } diff --git a/example/map/intersection.cpp b/example/map/intersection.cpp index 1dbe336dd9..1be8bf0b9b 100644 --- a/example/map/intersection.cpp +++ b/example/map/intersection.cpp @@ -13,35 +13,35 @@ namespace hana = boost::hana; using namespace hana::literals; -constexpr auto m1 = hana::make_map( - hana::make_pair("key1"_s, hana::type_c), - hana::make_pair("key2"_s, hana::type_c) +static auto m1 = hana::make_map( + hana::make_pair(BOOST_HANA_STRING("key1"), hana::type_c), + hana::make_pair(BOOST_HANA_STRING("key2"), hana::type_c) ); -constexpr auto m2 = hana::make_map( - hana::make_pair("key3"_s, hana::type_c), - hana::make_pair("key4"_s, hana::type_c), - hana::make_pair("key5"_s, hana::type_c) +static auto m2 = hana::make_map( + hana::make_pair(BOOST_HANA_STRING("key3"), hana::type_c), + hana::make_pair(BOOST_HANA_STRING("key4"), hana::type_c), + hana::make_pair(BOOST_HANA_STRING("key5"), hana::type_c) ); BOOST_HANA_CONSTANT_CHECK(hana::intersection(m1, m2) == hana::make_map()); -constexpr auto m3 = hana::make_map( +static auto m3 = hana::make_map( hana::make_pair(hana::type_c, hana::int_c<1>), hana::make_pair(hana::type_c, hana::bool_c), - hana::make_pair(hana::type_c, "hana"_s), + hana::make_pair(hana::type_c, BOOST_HANA_STRING("hana")), hana::make_pair(hana::type_c, hana::int_c<100>) ); -constexpr auto m4 = hana::make_map( +static auto m4 = hana::make_map( hana::make_pair(hana::type_c, hana::char_c<'c'>), hana::make_pair(hana::type_c, hana::bool_c), - hana::make_pair(hana::type_c, "boost"_s) + hana::make_pair(hana::type_c, BOOST_HANA_STRING("boost")) ); BOOST_HANA_CONSTANT_CHECK(hana::intersection(m3, m4) == hana::make_map( hana::make_pair(hana::type_c, hana::bool_c), - hana::make_pair(hana::type_c, "hana"_s) + hana::make_pair(hana::type_c, BOOST_HANA_STRING("hana")) )); int main() { } diff --git a/example/map/union.cpp b/example/map/union.cpp index 98afb1b480..d214b34df6 100644 --- a/example/map/union.cpp +++ b/example/map/union.cpp @@ -15,23 +15,23 @@ namespace hana = boost::hana; using namespace hana::literals; -constexpr auto m1 = hana::make_map( - hana::make_pair("key1"_s, hana::type_c), - hana::make_pair("key2"_s, hana::type_c) +static auto m1 = hana::make_map( + hana::make_pair(BOOST_HANA_STRING("key1"), hana::type_c), + hana::make_pair(BOOST_HANA_STRING("key2"), hana::type_c) ); -constexpr auto m2 = hana::make_map( - hana::make_pair("key3"_s, hana::type_c), - hana::make_pair("key4"_s, hana::type_c), - hana::make_pair("key5"_s, hana::type_c) +static auto m2 = hana::make_map( + hana::make_pair(BOOST_HANA_STRING("key3"), hana::type_c), + hana::make_pair(BOOST_HANA_STRING("key4"), hana::type_c), + hana::make_pair(BOOST_HANA_STRING("key5"), hana::type_c) ); BOOST_HANA_CONSTANT_CHECK(hana::union_(m1, m2) == hana::make_map( - hana::make_pair("key1"_s, hana::type_c), - hana::make_pair("key2"_s, hana::type_c), - hana::make_pair("key3"_s, hana::type_c), - hana::make_pair("key4"_s, hana::type_c), - hana::make_pair("key5"_s, hana::type_c) + hana::make_pair(BOOST_HANA_STRING("key1"), hana::type_c), + hana::make_pair(BOOST_HANA_STRING("key2"), hana::type_c), + hana::make_pair(BOOST_HANA_STRING("key3"), hana::type_c), + hana::make_pair(BOOST_HANA_STRING("key4"), hana::type_c), + hana::make_pair(BOOST_HANA_STRING("key5"), hana::type_c) )); constexpr auto m3 = hana::make_map( diff --git a/example/transform.cpp b/example/transform.cpp index fd330ba368..0bdf4cb09d 100644 --- a/example/transform.cpp +++ b/example/transform.cpp @@ -33,7 +33,7 @@ int main() { BOOST_HANA_RUNTIME_CHECK(hana::transform(hana::just(123), to_string) == hana::just("123"s)); BOOST_HANA_CONSTANT_CHECK( - hana::transform(hana::tuple_t, hana::template_) + hana::transform(hana::tuple_t, hana::metafunction) == hana::tuple_t ); 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>) ); diff --git a/example/tutorial/introspection.cpp b/example/tutorial/introspection.cpp index 4b53ecc934..3b72db447c 100644 --- a/example/tutorial/introspection.cpp +++ b/example/tutorial/introspection.cpp @@ -139,3 +139,20 @@ BOOST_HANA_CONSTANT_CHECK(has_member(hana::type_c)); BOOST_HANA_CONSTANT_CHECK(!has_member(hana::type_c)); //! [nested_template] } + +namespace template_specialization { +//! [template_specialization] +template +struct Foo; + +template +struct Bar; + +auto is_binary_template = hana::is_valid([](auto trait) -> decltype( + trait(hana::type_c, hana::type_c) +) { }); + +BOOST_HANA_CONSTANT_CHECK(is_binary_template(hana::template_)); +BOOST_HANA_CONSTANT_CHECK(!is_binary_template(hana::template_)); +//! [template_specialization] +} 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/experimental/printable.hpp b/include/boost/hana/experimental/printable.hpp index e24a3426ea..f41d3fd906 100644 --- a/include/boost/hana/experimental/printable.hpp +++ b/include/boost/hana/experimental/printable.hpp @@ -99,7 +99,7 @@ BOOST_HANA_NAMESPACE_BEGIN namespace experimental { namespace print_detail { std::string strip_type_junk(std::string const& str) { - return std::regex_replace(str, std::regex("^([a-z_]+::)*([a-z_]*)_t<"), "$2<"); + return std::regex_replace(str, std::regex("(?:struct )?([a-z_]+::)*([a-z_]*)_t<((?:struct )?[a-z:<>_]*)>"), "$2<$3>"); } } 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