184a50f59Szoecarver //===----------------------------------------------------------------------===//
284a50f59Szoecarver //
384a50f59Szoecarver // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
484a50f59Szoecarver // See https://llvm.org/LICENSE.txt for license information.
584a50f59Szoecarver // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
684a50f59Szoecarver //
784a50f59Szoecarver //===----------------------------------------------------------------------===//
884a50f59Szoecarver
9e35677c0SLouis Dionne // UNSUPPORTED: c++03, c++11, c++14, c++17
1084a50f59Szoecarver
1184a50f59Szoecarver // functional
1284a50f59Szoecarver
13f599e7a7SLouis Dionne // template <class F, class... Args>
14f599e7a7SLouis Dionne // constexpr unspecified bind_front(F&&, Args&&...);
1584a50f59Szoecarver
1684a50f59Szoecarver #include <functional>
17f599e7a7SLouis Dionne #include <cassert>
18f599e7a7SLouis Dionne #include <tuple>
19f599e7a7SLouis Dionne #include <type_traits>
20f599e7a7SLouis Dionne #include <utility>
2184a50f59Szoecarver
2284a50f59Szoecarver #include "callable_types.h"
2384a50f59Szoecarver #include "test_macros.h"
2484a50f59Szoecarver
2584a50f59Szoecarver struct CopyMoveInfo {
2684a50f59Szoecarver enum { none, copy, move } copy_kind;
2784a50f59Szoecarver
CopyMoveInfoCopyMoveInfo2884a50f59Szoecarver constexpr CopyMoveInfo() : copy_kind(none) {}
CopyMoveInfoCopyMoveInfo2984a50f59Szoecarver constexpr CopyMoveInfo(CopyMoveInfo const&) : copy_kind(copy) {}
CopyMoveInfoCopyMoveInfo3084a50f59Szoecarver constexpr CopyMoveInfo(CopyMoveInfo&&) : copy_kind(move) {}
3184a50f59Szoecarver };
3284a50f59Szoecarver
33f599e7a7SLouis Dionne template <class ...Args>
34f599e7a7SLouis Dionne struct is_bind_frontable {
35f599e7a7SLouis Dionne template <class ...LocalArgs>
36f599e7a7SLouis Dionne static auto test(int)
37f599e7a7SLouis Dionne -> decltype((void)std::bind_front(std::declval<LocalArgs>()...), std::true_type());
38f599e7a7SLouis Dionne
39f599e7a7SLouis Dionne template <class...>
40f599e7a7SLouis Dionne static std::false_type test(...);
41f599e7a7SLouis Dionne
42f599e7a7SLouis Dionne static constexpr bool value = decltype(test<Args...>(0))::value;
43f599e7a7SLouis Dionne };
44f599e7a7SLouis Dionne
45f599e7a7SLouis Dionne struct NotCopyMove {
46f599e7a7SLouis Dionne NotCopyMove() = delete;
47f599e7a7SLouis Dionne NotCopyMove(const NotCopyMove&) = delete;
48f599e7a7SLouis Dionne NotCopyMove(NotCopyMove&&) = delete;
49f599e7a7SLouis Dionne template <class ...Args>
operator ()NotCopyMove50f599e7a7SLouis Dionne void operator()(Args&& ...) const { }
51f599e7a7SLouis Dionne };
52f599e7a7SLouis Dionne
53f599e7a7SLouis Dionne struct NonConstCopyConstructible {
NonConstCopyConstructibleNonConstCopyConstructible54f599e7a7SLouis Dionne explicit NonConstCopyConstructible() {}
NonConstCopyConstructibleNonConstCopyConstructible55f599e7a7SLouis Dionne NonConstCopyConstructible(NonConstCopyConstructible&) {}
56f599e7a7SLouis Dionne };
57f599e7a7SLouis Dionne
58f599e7a7SLouis Dionne struct MoveConstructible {
MoveConstructibleMoveConstructible59f599e7a7SLouis Dionne explicit MoveConstructible() {}
MoveConstructibleMoveConstructible60f599e7a7SLouis Dionne MoveConstructible(MoveConstructible&&) {}
61f599e7a7SLouis Dionne };
62f599e7a7SLouis Dionne
63f599e7a7SLouis Dionne struct MakeTuple {
64f599e7a7SLouis Dionne template <class ...Args>
operator ()MakeTuple65f599e7a7SLouis Dionne constexpr auto operator()(Args&& ...args) const {
66f599e7a7SLouis Dionne return std::make_tuple(std::forward<Args>(args)...);
6784a50f59Szoecarver }
68f599e7a7SLouis Dionne };
69f599e7a7SLouis Dionne
70f599e7a7SLouis Dionne template <int X>
71f599e7a7SLouis Dionne struct Elem {
72f599e7a7SLouis Dionne template <int Y>
operator ==Elem73f599e7a7SLouis Dionne constexpr bool operator==(Elem<Y> const&) const
74f599e7a7SLouis Dionne { return X == Y; }
75f599e7a7SLouis Dionne };
76f599e7a7SLouis Dionne
test()77f599e7a7SLouis Dionne constexpr bool test() {
78f599e7a7SLouis Dionne // Bind arguments, call without arguments
79f599e7a7SLouis Dionne {
80f599e7a7SLouis Dionne {
81f599e7a7SLouis Dionne auto f = std::bind_front(MakeTuple{});
82f599e7a7SLouis Dionne assert(f() == std::make_tuple());
83f599e7a7SLouis Dionne }
84f599e7a7SLouis Dionne {
85f599e7a7SLouis Dionne auto f = std::bind_front(MakeTuple{}, Elem<1>{});
86f599e7a7SLouis Dionne assert(f() == std::make_tuple(Elem<1>{}));
87f599e7a7SLouis Dionne }
88f599e7a7SLouis Dionne {
89f599e7a7SLouis Dionne auto f = std::bind_front(MakeTuple{}, Elem<1>{}, Elem<2>{});
90f599e7a7SLouis Dionne assert(f() == std::make_tuple(Elem<1>{}, Elem<2>{}));
91f599e7a7SLouis Dionne }
92f599e7a7SLouis Dionne {
93f599e7a7SLouis Dionne auto f = std::bind_front(MakeTuple{}, Elem<1>{}, Elem<2>{}, Elem<3>{});
94f599e7a7SLouis Dionne assert(f() == std::make_tuple(Elem<1>{}, Elem<2>{}, Elem<3>{}));
95f599e7a7SLouis Dionne }
9684a50f59Szoecarver }
9784a50f59Szoecarver
98f599e7a7SLouis Dionne // Bind no arguments, call with arguments
99f599e7a7SLouis Dionne {
100f599e7a7SLouis Dionne {
101f599e7a7SLouis Dionne auto f = std::bind_front(MakeTuple{});
102f599e7a7SLouis Dionne assert(f(Elem<1>{}) == std::make_tuple(Elem<1>{}));
103f599e7a7SLouis Dionne }
104f599e7a7SLouis Dionne {
105f599e7a7SLouis Dionne auto f = std::bind_front(MakeTuple{});
106f599e7a7SLouis Dionne assert(f(Elem<1>{}, Elem<2>{}) == std::make_tuple(Elem<1>{}, Elem<2>{}));
107f599e7a7SLouis Dionne }
108f599e7a7SLouis Dionne {
109f599e7a7SLouis Dionne auto f = std::bind_front(MakeTuple{});
110f599e7a7SLouis Dionne assert(f(Elem<1>{}, Elem<2>{}, Elem<3>{}) == std::make_tuple(Elem<1>{}, Elem<2>{}, Elem<3>{}));
111f599e7a7SLouis Dionne }
112f599e7a7SLouis Dionne }
113f599e7a7SLouis Dionne
114f599e7a7SLouis Dionne // Bind arguments, call with arguments
115f599e7a7SLouis Dionne {
116f599e7a7SLouis Dionne {
117f599e7a7SLouis Dionne auto f = std::bind_front(MakeTuple{}, Elem<1>{});
118f599e7a7SLouis Dionne assert(f(Elem<10>{}) == std::make_tuple(Elem<1>{}, Elem<10>{}));
119f599e7a7SLouis Dionne }
120f599e7a7SLouis Dionne {
121f599e7a7SLouis Dionne auto f = std::bind_front(MakeTuple{}, Elem<1>{}, Elem<2>{});
122f599e7a7SLouis Dionne assert(f(Elem<10>{}) == std::make_tuple(Elem<1>{}, Elem<2>{}, Elem<10>{}));
123f599e7a7SLouis Dionne }
124f599e7a7SLouis Dionne {
125f599e7a7SLouis Dionne auto f = std::bind_front(MakeTuple{}, Elem<1>{}, Elem<2>{}, Elem<3>{});
126f599e7a7SLouis Dionne assert(f(Elem<10>{}) == std::make_tuple(Elem<1>{}, Elem<2>{}, Elem<3>{}, Elem<10>{}));
127f599e7a7SLouis Dionne }
128f599e7a7SLouis Dionne
129f599e7a7SLouis Dionne {
130f599e7a7SLouis Dionne auto f = std::bind_front(MakeTuple{}, Elem<1>{});
131f599e7a7SLouis Dionne assert(f(Elem<10>{}, Elem<11>{}) == std::make_tuple(Elem<1>{}, Elem<10>{}, Elem<11>{}));
132f599e7a7SLouis Dionne }
133f599e7a7SLouis Dionne {
134f599e7a7SLouis Dionne auto f = std::bind_front(MakeTuple{}, Elem<1>{}, Elem<2>{});
135f599e7a7SLouis Dionne assert(f(Elem<10>{}, Elem<11>{}) == std::make_tuple(Elem<1>{}, Elem<2>{}, Elem<10>{}, Elem<11>{}));
136f599e7a7SLouis Dionne }
137f599e7a7SLouis Dionne {
138f599e7a7SLouis Dionne auto f = std::bind_front(MakeTuple{}, Elem<1>{}, Elem<2>{}, Elem<3>{});
139f599e7a7SLouis Dionne assert(f(Elem<10>{}, Elem<11>{}) == std::make_tuple(Elem<1>{}, Elem<2>{}, Elem<3>{}, Elem<10>{}, Elem<11>{}));
140f599e7a7SLouis Dionne }
141f599e7a7SLouis Dionne }
142f599e7a7SLouis Dionne
143f599e7a7SLouis Dionne // Basic tests with fundamental types
144f599e7a7SLouis Dionne {
14584a50f59Szoecarver int n = 2;
14684a50f59Szoecarver int m = 1;
147f599e7a7SLouis Dionne auto add = [](int x, int y) { return x + y; };
148f599e7a7SLouis Dionne auto addN = [](int a, int b, int c, int d, int e, int f) {
149f599e7a7SLouis Dionne return a + b + c + d + e + f;
150f599e7a7SLouis Dionne };
15184a50f59Szoecarver
15284a50f59Szoecarver auto a = std::bind_front(add, m, n);
15384a50f59Szoecarver assert(a() == 3);
15484a50f59Szoecarver
155f599e7a7SLouis Dionne auto b = std::bind_front(addN, m, n, m, m, m, m);
15684a50f59Szoecarver assert(b() == 7);
15784a50f59Szoecarver
158f599e7a7SLouis Dionne auto c = std::bind_front(addN, n, m);
15984a50f59Szoecarver assert(c(1, 1, 1, 1) == 7);
16084a50f59Szoecarver
16184a50f59Szoecarver auto f = std::bind_front(add, n);
16284a50f59Szoecarver assert(f(3) == 5);
16384a50f59Szoecarver
16484a50f59Szoecarver auto g = std::bind_front(add, n, 1);
16584a50f59Szoecarver assert(g() == 3);
16684a50f59Szoecarver
167f599e7a7SLouis Dionne auto h = std::bind_front(addN, 1, 1, 1);
16884a50f59Szoecarver assert(h(2, 2, 2) == 9);
16984a50f59Szoecarver }
17084a50f59Szoecarver
171f599e7a7SLouis Dionne // Make sure we don't treat std::reference_wrapper specially.
172f599e7a7SLouis Dionne {
173f599e7a7SLouis Dionne auto add = [](std::reference_wrapper<int> a, std::reference_wrapper<int> b) {
174f599e7a7SLouis Dionne return a.get() + b.get();
17584a50f59Szoecarver };
176f599e7a7SLouis Dionne int i = 1, j = 2;
177f599e7a7SLouis Dionne auto f = std::bind_front(add, std::ref(i));
178f599e7a7SLouis Dionne assert(f(std::ref(j)) == 3);
17984a50f59Szoecarver }
18084a50f59Szoecarver
181f599e7a7SLouis Dionne // Make sure we can call a function that's a pointer to a member function.
182f599e7a7SLouis Dionne {
183f599e7a7SLouis Dionne struct MemberFunction {
184f599e7a7SLouis Dionne constexpr bool foo(int, int) { return true; }
18584a50f59Szoecarver };
186f599e7a7SLouis Dionne MemberFunction value;
187f599e7a7SLouis Dionne auto fn = std::bind_front(&MemberFunction::foo, value, 0);
18884a50f59Szoecarver assert(fn(0));
18984a50f59Szoecarver }
19084a50f59Szoecarver
191f599e7a7SLouis Dionne // Make sure that we copy the bound arguments into the unspecified-type.
192f599e7a7SLouis Dionne {
193f599e7a7SLouis Dionne auto add = [](int x, int y) { return x + y; };
194f599e7a7SLouis Dionne int n = 2;
195f599e7a7SLouis Dionne auto i = std::bind_front(add, n, 1);
196f599e7a7SLouis Dionne n = 100;
197f599e7a7SLouis Dionne assert(i() == 3);
19884a50f59Szoecarver }
19984a50f59Szoecarver
200f599e7a7SLouis Dionne // Make sure we pass the bound arguments to the function object
201f599e7a7SLouis Dionne // with the right value category.
202f599e7a7SLouis Dionne {
203f599e7a7SLouis Dionne {
204f599e7a7SLouis Dionne auto wasCopied = [](CopyMoveInfo info) {
205f599e7a7SLouis Dionne return info.copy_kind == CopyMoveInfo::copy;
206f599e7a7SLouis Dionne };
207f599e7a7SLouis Dionne CopyMoveInfo info;
208f599e7a7SLouis Dionne auto copied = std::bind_front(wasCopied, info);
209f599e7a7SLouis Dionne assert(copied());
210f599e7a7SLouis Dionne }
21184a50f59Szoecarver
212f599e7a7SLouis Dionne {
213f599e7a7SLouis Dionne auto wasMoved = [](CopyMoveInfo info) {
214f599e7a7SLouis Dionne return info.copy_kind == CopyMoveInfo::move;
215f599e7a7SLouis Dionne };
216f599e7a7SLouis Dionne CopyMoveInfo info;
217f599e7a7SLouis Dionne auto moved = std::bind_front(wasMoved, info);
218f599e7a7SLouis Dionne assert(std::move(moved)());
219f599e7a7SLouis Dionne }
220f599e7a7SLouis Dionne }
221f599e7a7SLouis Dionne
222f599e7a7SLouis Dionne // Make sure we call the correctly cv-ref qualified operator() based on the
223f599e7a7SLouis Dionne // value category of the bind_front unspecified-type.
224f599e7a7SLouis Dionne {
225f599e7a7SLouis Dionne struct F {
226f599e7a7SLouis Dionne constexpr int operator()() & { return 1; }
227f599e7a7SLouis Dionne constexpr int operator()() const& { return 2; }
228f599e7a7SLouis Dionne constexpr int operator()() && { return 3; }
229f599e7a7SLouis Dionne constexpr int operator()() const&& { return 4; }
230f599e7a7SLouis Dionne };
231f599e7a7SLouis Dionne auto x = std::bind_front(F{});
232f599e7a7SLouis Dionne using X = decltype(x);
233f599e7a7SLouis Dionne assert(static_cast<X&>(x)() == 1);
234f599e7a7SLouis Dionne assert(static_cast<X const&>(x)() == 2);
235f599e7a7SLouis Dionne assert(static_cast<X&&>(x)() == 3);
236f599e7a7SLouis Dionne assert(static_cast<X const&&>(x)() == 4);
237f599e7a7SLouis Dionne }
238f599e7a7SLouis Dionne
239f599e7a7SLouis Dionne // Make sure the bind_front unspecified-type is NOT invocable when the call would select a
240f599e7a7SLouis Dionne // differently-qualified operator().
241f599e7a7SLouis Dionne //
242f599e7a7SLouis Dionne // For example, if the call to `operator()() &` is ill-formed, the call to the unspecified-type
243f599e7a7SLouis Dionne // should be ill-formed and not fall back to the `operator()() const&` overload.
244f599e7a7SLouis Dionne {
245f599e7a7SLouis Dionne // Make sure we delete the & overload when the underlying call isn't valid
246f599e7a7SLouis Dionne {
247f599e7a7SLouis Dionne struct F {
248f599e7a7SLouis Dionne void operator()() & = delete;
249f599e7a7SLouis Dionne void operator()() const&;
250f599e7a7SLouis Dionne void operator()() &&;
251f599e7a7SLouis Dionne void operator()() const&&;
252f599e7a7SLouis Dionne };
253f599e7a7SLouis Dionne using X = decltype(std::bind_front(F{}));
254f599e7a7SLouis Dionne static_assert(!std::is_invocable_v<X&>);
255f599e7a7SLouis Dionne static_assert( std::is_invocable_v<X const&>);
256f599e7a7SLouis Dionne static_assert( std::is_invocable_v<X>);
257f599e7a7SLouis Dionne static_assert( std::is_invocable_v<X const>);
258f599e7a7SLouis Dionne }
259f599e7a7SLouis Dionne
260f599e7a7SLouis Dionne // There's no way to make sure we delete the const& overload when the underlying call isn't valid,
261f599e7a7SLouis Dionne // so we can't check this one.
262f599e7a7SLouis Dionne
263f599e7a7SLouis Dionne // Make sure we delete the && overload when the underlying call isn't valid
264f599e7a7SLouis Dionne {
265f599e7a7SLouis Dionne struct F {
266f599e7a7SLouis Dionne void operator()() &;
267f599e7a7SLouis Dionne void operator()() const&;
268f599e7a7SLouis Dionne void operator()() && = delete;
269f599e7a7SLouis Dionne void operator()() const&&;
270f599e7a7SLouis Dionne };
271f599e7a7SLouis Dionne using X = decltype(std::bind_front(F{}));
272f599e7a7SLouis Dionne static_assert( std::is_invocable_v<X&>);
273f599e7a7SLouis Dionne static_assert( std::is_invocable_v<X const&>);
274f599e7a7SLouis Dionne static_assert(!std::is_invocable_v<X>);
275f599e7a7SLouis Dionne static_assert( std::is_invocable_v<X const>);
276f599e7a7SLouis Dionne }
277f599e7a7SLouis Dionne
278f599e7a7SLouis Dionne // Make sure we delete the const&& overload when the underlying call isn't valid
279f599e7a7SLouis Dionne {
280f599e7a7SLouis Dionne struct F {
281f599e7a7SLouis Dionne void operator()() &;
282f599e7a7SLouis Dionne void operator()() const&;
283f599e7a7SLouis Dionne void operator()() &&;
284f599e7a7SLouis Dionne void operator()() const&& = delete;
285f599e7a7SLouis Dionne };
286f599e7a7SLouis Dionne using X = decltype(std::bind_front(F{}));
287f599e7a7SLouis Dionne static_assert( std::is_invocable_v<X&>);
288f599e7a7SLouis Dionne static_assert( std::is_invocable_v<X const&>);
289f599e7a7SLouis Dionne static_assert( std::is_invocable_v<X>);
290f599e7a7SLouis Dionne static_assert(!std::is_invocable_v<X const>);
291f599e7a7SLouis Dionne }
292f599e7a7SLouis Dionne }
293f599e7a7SLouis Dionne
294f599e7a7SLouis Dionne // Some examples by Tim Song
295f599e7a7SLouis Dionne {
296f599e7a7SLouis Dionne {
297f599e7a7SLouis Dionne struct T { };
298f599e7a7SLouis Dionne struct F {
299f599e7a7SLouis Dionne void operator()(T&&) const &;
300f599e7a7SLouis Dionne void operator()(T&&) && = delete;
301f599e7a7SLouis Dionne };
302f599e7a7SLouis Dionne using X = decltype(std::bind_front(F{}));
303f599e7a7SLouis Dionne static_assert(!std::is_invocable_v<X, T>);
304f599e7a7SLouis Dionne }
305f599e7a7SLouis Dionne
306f599e7a7SLouis Dionne {
307f599e7a7SLouis Dionne struct T { };
308f599e7a7SLouis Dionne struct F {
309f599e7a7SLouis Dionne void operator()(T const&) const;
310f599e7a7SLouis Dionne void operator()(T&&) const = delete;
311f599e7a7SLouis Dionne };
312f599e7a7SLouis Dionne using X = decltype(std::bind_front(F{}, T{}));
313f599e7a7SLouis Dionne static_assert(!std::is_invocable_v<X>);
314f599e7a7SLouis Dionne }
315f599e7a7SLouis Dionne }
316f599e7a7SLouis Dionne
317f599e7a7SLouis Dionne // Test properties of the constructor of the unspecified-type returned by bind_front.
318f599e7a7SLouis Dionne {
31984a50f59Szoecarver {
32084a50f59Szoecarver MoveOnlyCallable value(true);
32184a50f59Szoecarver auto ret = std::bind_front(std::move(value), 1);
32284a50f59Szoecarver assert(ret());
32384a50f59Szoecarver assert(ret(1, 2, 3));
32484a50f59Szoecarver
32584a50f59Szoecarver auto ret1 = std::move(ret);
32684a50f59Szoecarver assert(!ret());
32784a50f59Szoecarver assert(ret1());
32884a50f59Szoecarver assert(ret1(1, 2, 3));
329ce96d81cSLouis Dionne
330ce96d81cSLouis Dionne using RetT = decltype(ret);
331ce96d81cSLouis Dionne static_assert( std::is_move_constructible<RetT>::value);
332ce96d81cSLouis Dionne static_assert(!std::is_copy_constructible<RetT>::value);
333ce96d81cSLouis Dionne static_assert(!std::is_move_assignable<RetT>::value);
334ce96d81cSLouis Dionne static_assert(!std::is_copy_assignable<RetT>::value);
33584a50f59Szoecarver }
33684a50f59Szoecarver {
33784a50f59Szoecarver CopyCallable value(true);
33884a50f59Szoecarver auto ret = std::bind_front(value, 1);
33984a50f59Szoecarver assert(ret());
34084a50f59Szoecarver assert(ret(1, 2, 3));
34184a50f59Szoecarver
34284a50f59Szoecarver auto ret1 = std::move(ret);
34384a50f59Szoecarver assert(ret1());
34484a50f59Szoecarver assert(ret1(1, 2, 3));
34584a50f59Szoecarver
34684a50f59Szoecarver auto ret2 = std::bind_front(std::move(value), 1);
34784a50f59Szoecarver assert(!ret());
34884a50f59Szoecarver assert(ret2());
34984a50f59Szoecarver assert(ret2(1, 2, 3));
350ce96d81cSLouis Dionne
351ce96d81cSLouis Dionne using RetT = decltype(ret);
352ce96d81cSLouis Dionne static_assert( std::is_move_constructible<RetT>::value);
353ce96d81cSLouis Dionne static_assert( std::is_copy_constructible<RetT>::value);
354ce96d81cSLouis Dionne static_assert(!std::is_move_assignable<RetT>::value);
355ce96d81cSLouis Dionne static_assert(!std::is_copy_assignable<RetT>::value);
35684a50f59Szoecarver }
35784a50f59Szoecarver {
35884a50f59Szoecarver CopyAssignableWrapper value(true);
35984a50f59Szoecarver using RetT = decltype(std::bind_front(value, 1));
36084a50f59Szoecarver
36184a50f59Szoecarver static_assert(std::is_move_constructible<RetT>::value);
36284a50f59Szoecarver static_assert(std::is_copy_constructible<RetT>::value);
36384a50f59Szoecarver static_assert(std::is_move_assignable<RetT>::value);
36484a50f59Szoecarver static_assert(std::is_copy_assignable<RetT>::value);
36584a50f59Szoecarver }
36684a50f59Szoecarver {
36784a50f59Szoecarver MoveAssignableWrapper value(true);
36884a50f59Szoecarver using RetT = decltype(std::bind_front(std::move(value), 1));
36984a50f59Szoecarver
37084a50f59Szoecarver static_assert( std::is_move_constructible<RetT>::value);
37184a50f59Szoecarver static_assert(!std::is_copy_constructible<RetT>::value);
37284a50f59Szoecarver static_assert( std::is_move_assignable<RetT>::value);
37384a50f59Szoecarver static_assert(!std::is_copy_assignable<RetT>::value);
37484a50f59Szoecarver }
37584a50f59Szoecarver }
37684a50f59Szoecarver
377f599e7a7SLouis Dionne // Make sure bind_front is SFINAE friendly
378f599e7a7SLouis Dionne {
379f599e7a7SLouis Dionne static_assert(!std::is_constructible_v<NotCopyMove, NotCopyMove&>);
38084a50f59Szoecarver static_assert(!std::is_move_constructible_v<NotCopyMove>);
38184a50f59Szoecarver static_assert(!is_bind_frontable<NotCopyMove>::value);
38284a50f59Szoecarver static_assert(!is_bind_frontable<NotCopyMove&>::value);
38384a50f59Szoecarver
384f599e7a7SLouis Dionne auto takeAnything = [](auto&& ...) { };
385f599e7a7SLouis Dionne static_assert(!std::is_constructible_v<MoveConstructible, MoveConstructible&>);
38684a50f59Szoecarver static_assert( std::is_move_constructible_v<MoveConstructible>);
387f599e7a7SLouis Dionne static_assert( is_bind_frontable<decltype(takeAnything), MoveConstructible>::value);
388f599e7a7SLouis Dionne static_assert(!is_bind_frontable<decltype(takeAnything), MoveConstructible&>::value);
38984a50f59Szoecarver
390f599e7a7SLouis Dionne static_assert( std::is_constructible_v<NonConstCopyConstructible, NonConstCopyConstructible&>);
39184a50f59Szoecarver static_assert(!std::is_move_constructible_v<NonConstCopyConstructible>);
392f599e7a7SLouis Dionne static_assert(!is_bind_frontable<decltype(takeAnything), NonConstCopyConstructible&>::value);
393f599e7a7SLouis Dionne static_assert(!is_bind_frontable<decltype(takeAnything), NonConstCopyConstructible>::value);
39484a50f59Szoecarver }
39584a50f59Szoecarver
396*89a7bdb1SLouis Dionne // Make sure bind_front's unspecified type's operator() is SFINAE-friendly
397*89a7bdb1SLouis Dionne {
398*89a7bdb1SLouis Dionne using T = decltype(std::bind_front(std::declval<int(*)(int, int)>(), 1));
399*89a7bdb1SLouis Dionne static_assert(!std::is_invocable<T>::value);
400*89a7bdb1SLouis Dionne static_assert( std::is_invocable<T, int>::value);
401*89a7bdb1SLouis Dionne static_assert(!std::is_invocable<T, void*>::value);
402*89a7bdb1SLouis Dionne static_assert(!std::is_invocable<T, int, int>::value);
403*89a7bdb1SLouis Dionne }
404*89a7bdb1SLouis Dionne
40584a50f59Szoecarver return true;
40684a50f59Szoecarver }
40784a50f59Szoecarver
main(int,char **)40884a50f59Szoecarver int main(int, char**) {
40984a50f59Szoecarver test();
41084a50f59Szoecarver static_assert(test());
41184a50f59Szoecarver
41284a50f59Szoecarver return 0;
41384a50f59Szoecarver }
414