hana/example/tutorial/introspection.cpp
Louis Dionne c334974abe [type] Make metafunction & friends SFINAE friendly
Also add a section to the tutorial showing how to use this functionality.
2018-06-19 21:07:14 -07:00

159 lines
4.1 KiB
C++

// 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 <boost/hana.hpp>
#include <string>
#include <type_traits>
#include <utility>
namespace hana = boost::hana;
struct yes { std::string toString() const { return "yes"; } };
struct no { };
namespace has_toString_then {
//! [has_toString.then]
template <typename T, typename = void>
struct has_toString
: std::false_type
{ };
template <typename T>
struct has_toString<T, decltype((void)std::declval<T>().toString())>
: std::true_type
{ };
//! [has_toString.then]
static_assert(has_toString<yes>::value, "");
static_assert(!has_toString<no>::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 <typename T>
auto optionalToString(T const& obj)
-> std::enable_if_t<decltype(has_toString(obj))::value, std::string>
{ return obj.toString(); }
template <typename T>
auto optionalToString(T const& obj)
-> std::enable_if_t<decltype(!has_toString(obj))::value, std::string>
{ return "toString not defined"; }
//! [optionalToString.then]
// make sure they compile
template std::string optionalToString(yes const&);
template std::string optionalToString(no const&);
}
//! [optionalToString]
template <typename T>
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<Foo>));
BOOST_HANA_CONSTANT_CHECK(!has_member(hana::type_c<Bar>));
//! [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<Foo>));
BOOST_HANA_CONSTANT_CHECK(!has_member(hana::type_c<Bar>));
//! [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<Foo>));
BOOST_HANA_CONSTANT_CHECK(!has_member(hana::type_c<Bar>));
//! [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 <typename ...> struct member; };
struct Bar { };
BOOST_HANA_CONSTANT_CHECK(has_member(hana::type_c<Foo>));
BOOST_HANA_CONSTANT_CHECK(!has_member(hana::type_c<Bar>));
//! [nested_template]
}
namespace template_specialization {
//! [template_specialization]
template <typename T, typename U>
struct Foo;
template <typename T>
struct Bar;
auto is_binary_template = hana::is_valid([](auto trait) -> decltype(
trait(hana::type_c<void>, hana::type_c<void>)
) { });
BOOST_HANA_CONSTANT_CHECK(is_binary_template(hana::template_<Foo>));
BOOST_HANA_CONSTANT_CHECK(!is_binary_template(hana::template_<Bar>));
//! [template_specialization]
}