// Copyright Louis Dionne 2013-2017 // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt) #include #include #include #include namespace hana = boost::hana; struct yes { std::string toString() const { return "yes"; } }; struct no { }; namespace has_toString_then { //! [has_toString.then] template struct has_toString : std::false_type { }; template struct has_toString().toString())> : std::true_type { }; //! [has_toString.then] static_assert(has_toString::value, ""); static_assert(!has_toString::value, ""); } //! [has_toString.now] auto has_toString = hana::is_valid([](auto&& obj) -> decltype(obj.toString()) { }); //! [has_toString.now] BOOST_HANA_CONSTANT_CHECK(has_toString(yes{})); BOOST_HANA_CONSTANT_CHECK(hana::not_(has_toString(no{}))); namespace optionalToString_then { //! [optionalToString.then] template auto optionalToString(T const& obj) -> std::enable_if_t { return obj.toString(); } template auto optionalToString(T const& obj) -> std::enable_if_t { return "toString not defined"; } //! [optionalToString.then] // make sure they compile template std::string optionalToString(yes const&); template std::string optionalToString(no const&); } //! [optionalToString] template std::string optionalToString(T const& obj) { return hana::if_(has_toString(obj), [](auto& x) { return x.toString(); }, [](auto& x) { return "toString not defined"; } )(obj); } //! [optionalToString] int main() { BOOST_HANA_RUNTIME_CHECK(optionalToString(yes{}) == "yes"); BOOST_HANA_RUNTIME_CHECK(optionalToString(no{}) == "toString not defined"); { //! [non_static_member_from_object] auto has_member = hana::is_valid([](auto&& x) -> decltype((void)x.member) { }); struct Foo { int member[4]; }; struct Bar { }; BOOST_HANA_CONSTANT_CHECK(has_member(Foo{})); BOOST_HANA_CONSTANT_CHECK(!has_member(Bar{})); //! [non_static_member_from_object] }{ //! [non_static_member_from_type] auto has_member = hana::is_valid([](auto t) -> decltype( (void)hana::traits::declval(t).member ) { }); struct Foo { int member[4]; }; struct Bar { }; BOOST_HANA_CONSTANT_CHECK(has_member(hana::type_c)); BOOST_HANA_CONSTANT_CHECK(!has_member(hana::type_c)); //! [non_static_member_from_type] }{ //! [nested_type_name] auto has_member = hana::is_valid([](auto t) -> hana::type< typename decltype(t)::type::member //^^^^^^^^ needed because of the dependent context > { }); struct Foo { struct member; /* not defined! */ }; struct Bar { }; BOOST_HANA_CONSTANT_CHECK(has_member(hana::type_c)); BOOST_HANA_CONSTANT_CHECK(!has_member(hana::type_c)); //! [nested_type_name] } } namespace static_member { //! [static_member] auto has_member = hana::is_valid([](auto t) -> decltype( (void)decltype(t)::type::member ) { }); struct Foo { static int member[4]; }; struct Bar { }; BOOST_HANA_CONSTANT_CHECK(has_member(hana::type_c)); BOOST_HANA_CONSTANT_CHECK(!has_member(hana::type_c)); //! [static_member] } namespace nested_template { //! [nested_template] auto has_member = hana::is_valid([](auto t) -> decltype(hana::template_< decltype(t)::type::template member // ^^^^^^^^ needed because of the dependent context >) { }); struct Foo { template struct member; }; struct Bar { }; 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] }