1 // Copyright Louis Dionne 2013-2017
2 // Distributed under the Boost Software License, Version 1.0.
3 // (See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt)
5 #include <boost/hana/assert.hpp>
6 #include <boost/hana/equal.hpp>
7 #include <boost/hana/not.hpp>
8 #include <boost/hana/traits.hpp>
9 #include <boost/hana/type.hpp>
11 #include <support/tracked.hpp>
13 #include <type_traits>
14 namespace hana
= boost::hana
;
19 struct static_nested_member
{ static const int member
= 1; };
20 struct static_nested_member_array
{ static int member
[3]; };
21 struct nested_template_struct
{ template <typename
...> struct nested
; };
22 struct nested_template_alias
{ template <typename
...> using nested
= void; };
25 // Check for a non-static member
27 struct yes
{ int member
; };
30 auto from_type
= hana::is_valid([](auto t
) -> decltype(
31 hana::traits::declval(t
).member
33 BOOST_HANA_CONSTANT_CHECK(from_type(hana::type_c
<yes
>));
34 BOOST_HANA_CONSTANT_CHECK(hana::not_(from_type(hana::type_c
<no
>)));
36 auto from_object
= hana::is_valid([](auto&& t
) -> decltype(
39 BOOST_HANA_CONSTANT_CHECK(from_object(yes
{}));
40 BOOST_HANA_CONSTANT_CHECK(hana::not_(from_object(no
{})));
43 // Check for a static member
45 using yes
= static_nested_member
;
48 auto from_type
= hana::is_valid([](auto t
) -> decltype(
49 decltype(t
)::type::member
51 BOOST_HANA_CONSTANT_CHECK(from_type(hana::type_c
<yes
>));
52 BOOST_HANA_CONSTANT_CHECK(hana::not_(from_type(hana::type_c
<no
>)));
54 auto from_object
= hana::is_valid([](auto&& t
) -> decltype(
55 std::remove_reference_t
<decltype(t
)>::member
57 BOOST_HANA_CONSTANT_CHECK(from_object(yes
{}));
58 BOOST_HANA_CONSTANT_CHECK(hana::not_(from_object(no
{})));
61 // Check for a nested type
63 struct yes
{ using nested
= void; };
66 auto from_type
= hana::is_valid([](auto t
) -> decltype(hana::type_c
<
67 typename
decltype(t
)::type::nested
69 BOOST_HANA_CONSTANT_CHECK(from_type(hana::type_c
<yes
>));
70 BOOST_HANA_CONSTANT_CHECK(hana::not_(from_type(hana::type_c
<no
>)));
72 auto from_object
= hana::is_valid([](auto&& t
) -> decltype(hana::type_c
<
73 typename
std::remove_reference_t
<decltype(t
)>::nested
75 BOOST_HANA_CONSTANT_CHECK(from_object(yes
{}));
76 BOOST_HANA_CONSTANT_CHECK(hana::not_(from_object(no
{})));
79 // Check for a nested template
82 using yes
= nested_template_struct
;
85 auto from_type
= hana::is_valid([](auto t
) -> decltype(hana::template_
<
86 decltype(t
)::type::template nested
88 BOOST_HANA_CONSTANT_CHECK(from_type(hana::type_c
<yes
>));
89 BOOST_HANA_CONSTANT_CHECK(hana::not_(from_type(hana::type_c
<no
>)));
91 auto from_object
= hana::is_valid([](auto&& t
) -> decltype(hana::template_
<
92 std::remove_reference_t
<decltype(t
)>::template nested
94 BOOST_HANA_CONSTANT_CHECK(from_object(yes
{}));
95 BOOST_HANA_CONSTANT_CHECK(hana::not_(from_object(no
{})));
99 using yes
= nested_template_alias
;
102 auto from_type
= hana::is_valid([](auto t
) -> decltype(hana::template_
<
103 decltype(t
)::type::template nested
105 BOOST_HANA_CONSTANT_CHECK(from_type(hana::type_c
<yes
>));
106 BOOST_HANA_CONSTANT_CHECK(hana::not_(from_type(hana::type_c
<no
>)));
108 auto from_object
= hana::is_valid([](auto&& t
) -> decltype(hana::template_
<
109 std::remove_reference_t
<decltype(t
)>::template nested
111 BOOST_HANA_CONSTANT_CHECK(from_object(yes
{}));
112 BOOST_HANA_CONSTANT_CHECK(hana::not_(from_object(no
{})));
116 // Make sure that checking for a nested static or non-static member
117 // works even when the type of that member is an array type or
118 // something that can't be returned from a function.
120 { // non-static member
121 struct yes
{ int member
[3]; };
124 auto from_type
= hana::is_valid([](auto t
) -> decltype(
125 (void)hana::traits::declval(t
).member
127 BOOST_HANA_CONSTANT_CHECK(from_type(hana::type_c
<yes
>));
128 BOOST_HANA_CONSTANT_CHECK(hana::not_(from_type(hana::type_c
<no
>)));
130 auto from_object
= hana::is_valid([](auto&& t
) -> decltype(
133 BOOST_HANA_CONSTANT_CHECK(from_object(yes
{}));
134 BOOST_HANA_CONSTANT_CHECK(hana::not_(from_object(no
{})));
138 using yes
= static_nested_member_array
;
141 auto from_type
= hana::is_valid([](auto t
) -> decltype(
142 (void)decltype(t
)::type::member
144 BOOST_HANA_CONSTANT_CHECK(from_type(hana::type_c
<yes
>));
145 BOOST_HANA_CONSTANT_CHECK(hana::not_(from_type(hana::type_c
<no
>)));
147 auto from_object
= hana::is_valid([](auto&& t
) -> decltype(
148 (void)std::remove_reference_t
<decltype(t
)>::member
150 BOOST_HANA_CONSTANT_CHECK(from_object(yes
{}));
151 BOOST_HANA_CONSTANT_CHECK(hana::not_(from_object(no
{})));
155 // Make sure the result of a `is_valid` function is constexpr
156 // even when called on non-constexpr arguments.
159 auto f
= hana::is_valid([](auto) { });
160 constexpr auto result
= f(i
);
164 // Make sure `is_valid` works with non-PODs.
166 hana::is_valid(undefined
{})(Tracked
{1});
167 hana::is_valid([t
= Tracked
{1}](auto) { return 1; })(Tracked
{1});
170 // Check `is_valid` with a nullary function.
172 auto f
= [](auto ...x
) { (void)sizeof...(x
); /* -Wunused-param */ };
173 auto g
= [](auto ...x
) -> char(*)[sizeof...(x
)] { };
174 BOOST_HANA_CONSTANT_CHECK(hana::is_valid(f
)());
175 BOOST_HANA_CONSTANT_CHECK(hana::not_(hana::is_valid(g
)()));
178 // Call `is_valid` in the non-curried form.
180 struct yes
{ int member
; };
183 auto f
= [](auto&& t
) -> decltype(t
.member
) { };
185 BOOST_HANA_CONSTANT_CHECK(hana::is_valid(f
, yes
{}));
186 BOOST_HANA_CONSTANT_CHECK(hana::not_(hana::is_valid(f
, no
{})));