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)
4 
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>
10 
11 #include <support/tracked.hpp>
12 
13 #include <type_traits>
14 namespace hana = boost::hana;
15 
16 
17 struct undefined { };
18 
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; };
23 
main()24 int main() {
25     // Check for a non-static member
26     {
27         struct yes { int member; };
28         struct no { };
29 
30         auto from_type = hana::is_valid([](auto t) -> decltype(
31             hana::traits::declval(t).member
32         ) { });
33         BOOST_HANA_CONSTANT_CHECK(from_type(hana::type_c<yes>));
34         BOOST_HANA_CONSTANT_CHECK(hana::not_(from_type(hana::type_c<no>)));
35 
36         auto from_object = hana::is_valid([](auto&& t) -> decltype(
37             t.member
38         ) { });
39         BOOST_HANA_CONSTANT_CHECK(from_object(yes{}));
40         BOOST_HANA_CONSTANT_CHECK(hana::not_(from_object(no{})));
41     }
42 
43     // Check for a non-static member function
44     {
45         struct yes { int member() const; };
46         struct no { };
47 
48         auto from_type = hana::is_valid([](auto t) -> decltype(
49             hana::traits::declval(t).member()
50         ) { });
51         BOOST_HANA_CONSTANT_CHECK(from_type(hana::type_c<yes>));
52         BOOST_HANA_CONSTANT_CHECK(hana::not_(from_type(hana::type_c<no>)));
53 
54         auto from_object = hana::is_valid([](auto&& t) -> decltype(
55             t.member()
56         ) { });
57         BOOST_HANA_CONSTANT_CHECK(from_object(yes{}));
58         BOOST_HANA_CONSTANT_CHECK(hana::not_(from_object(no{})));
59     }
60 
61     // Check for a static member
62     {
63         using yes = static_nested_member;
64         struct no { };
65 
66         auto from_type = hana::is_valid([](auto t) -> decltype(
67             decltype(t)::type::member
68         ) { });
69         BOOST_HANA_CONSTANT_CHECK(from_type(hana::type_c<yes>));
70         BOOST_HANA_CONSTANT_CHECK(hana::not_(from_type(hana::type_c<no>)));
71 
72         auto from_object = hana::is_valid([](auto&& t) -> decltype(
73             std::remove_reference_t<decltype(t)>::member
74         ) { });
75         BOOST_HANA_CONSTANT_CHECK(from_object(yes{}));
76         BOOST_HANA_CONSTANT_CHECK(hana::not_(from_object(no{})));
77     }
78 
79     // Check for a nested type
80     {
81         struct yes { using nested = void; };
82         struct no { };
83 
84         auto from_type = hana::is_valid([](auto t) -> decltype(hana::type_c<
85             typename decltype(t)::type::nested
86         >) { });
87         BOOST_HANA_CONSTANT_CHECK(from_type(hana::type_c<yes>));
88         BOOST_HANA_CONSTANT_CHECK(hana::not_(from_type(hana::type_c<no>)));
89 
90         auto from_object = hana::is_valid([](auto&& t) -> decltype(hana::type_c<
91             typename std::remove_reference_t<decltype(t)>::nested
92         >) { });
93         BOOST_HANA_CONSTANT_CHECK(from_object(yes{}));
94         BOOST_HANA_CONSTANT_CHECK(hana::not_(from_object(no{})));
95     }
96 
97     // Check for a nested template
98     {
99         { // template struct
100         using yes = nested_template_struct;
101         struct no { };
102 
103         auto from_type = hana::is_valid([](auto t) -> decltype(hana::template_<
104             decltype(t)::type::template nested
105         >) { });
106         BOOST_HANA_CONSTANT_CHECK(from_type(hana::type_c<yes>));
107         BOOST_HANA_CONSTANT_CHECK(hana::not_(from_type(hana::type_c<no>)));
108 
109         auto from_object = hana::is_valid([](auto&& t) -> decltype(hana::template_<
110             std::remove_reference_t<decltype(t)>::template nested
111         >) { });
112         BOOST_HANA_CONSTANT_CHECK(from_object(yes{}));
113         BOOST_HANA_CONSTANT_CHECK(hana::not_(from_object(no{})));
114         }
115 
116         { // template alias
117         using yes = nested_template_alias;
118         struct no { };
119 
120         auto from_type = hana::is_valid([](auto t) -> decltype(hana::template_<
121             decltype(t)::type::template nested
122         >) { });
123         BOOST_HANA_CONSTANT_CHECK(from_type(hana::type_c<yes>));
124         BOOST_HANA_CONSTANT_CHECK(hana::not_(from_type(hana::type_c<no>)));
125 
126         auto from_object = hana::is_valid([](auto&& t) -> decltype(hana::template_<
127             std::remove_reference_t<decltype(t)>::template nested
128         >) { });
129         BOOST_HANA_CONSTANT_CHECK(from_object(yes{}));
130         BOOST_HANA_CONSTANT_CHECK(hana::not_(from_object(no{})));
131         }
132     }
133 
134     // Make sure that checking for a nested static or non-static member
135     // works even when the type of that member is an array type or
136     // something that can't be returned from a function.
137     {
138         { // non-static member
139         struct yes { int member[3]; };
140         struct no { };
141 
142         auto from_type = hana::is_valid([](auto t) -> decltype(
143             (void)hana::traits::declval(t).member
144         ) { });
145         BOOST_HANA_CONSTANT_CHECK(from_type(hana::type_c<yes>));
146         BOOST_HANA_CONSTANT_CHECK(hana::not_(from_type(hana::type_c<no>)));
147 
148         auto from_object = hana::is_valid([](auto&& t) -> decltype(
149             (void)t.member
150         ) { });
151         BOOST_HANA_CONSTANT_CHECK(from_object(yes{}));
152         BOOST_HANA_CONSTANT_CHECK(hana::not_(from_object(no{})));
153         }
154 
155         { // static member
156         using yes = static_nested_member_array;
157         struct no { };
158 
159         auto from_type = hana::is_valid([](auto t) -> decltype(
160             (void)decltype(t)::type::member
161         ) { });
162         BOOST_HANA_CONSTANT_CHECK(from_type(hana::type_c<yes>));
163         BOOST_HANA_CONSTANT_CHECK(hana::not_(from_type(hana::type_c<no>)));
164 
165         auto from_object = hana::is_valid([](auto&& t) -> decltype(
166             (void)std::remove_reference_t<decltype(t)>::member
167         ) { });
168         BOOST_HANA_CONSTANT_CHECK(from_object(yes{}));
169         BOOST_HANA_CONSTANT_CHECK(hana::not_(from_object(no{})));
170         }
171     }
172 
173     // Make sure the result of a `is_valid` function is constexpr
174     // even when called on non-constexpr arguments.
175     {
176         int i;
177         auto f = hana::is_valid([](auto) { });
178         constexpr auto result = f(i);
179         (void)result;
180     }
181 
182     // Make sure `is_valid` works with non-PODs.
183     {
184         hana::is_valid(undefined{})(Tracked{1});
185         hana::is_valid([t = Tracked{1}](auto) { return 1; })(Tracked{1});
186     }
187 
188     // Check `is_valid` with a nullary function.
189     {
190         auto f = [](auto ...x) { (void)sizeof...(x); /* -Wunused-param */ };
191         auto g = [](auto ...x) -> char(*)[sizeof...(x)] { };
192         BOOST_HANA_CONSTANT_CHECK(hana::is_valid(f)());
193         BOOST_HANA_CONSTANT_CHECK(hana::not_(hana::is_valid(g)()));
194     }
195 
196     // Call `is_valid` in the non-curried form.
197     {
198         struct yes { int member; };
199         struct no { };
200 
201         auto f = [](auto&& t) -> decltype(t.member) { };
202 
203         BOOST_HANA_CONSTANT_CHECK(hana::is_valid(f, yes{}));
204         BOOST_HANA_CONSTANT_CHECK(hana::not_(hana::is_valid(f, no{})));
205     }
206 }
207