| // Copyright (C) 2014-2021 Free Software Foundation, Inc. |
| // |
| // This file is part of the GNU ISO C++ Library. This library is free |
| // software; you can redistribute it and/or modify it under the |
| // terms of the GNU General Public License as published by the |
| // Free Software Foundation; either version 3, or (at your option) |
| // any later version. |
| |
| // This library is distributed in the hope that it will be useful, |
| // but WITHOUT ANY WARRANTY; without even the implied warranty of |
| // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| // GNU General Public License for more details. |
| |
| // You should have received a copy of the GNU General Public License along |
| // with this library; see the file COPYING3. If not see |
| // <http://www.gnu.org/licenses/>. |
| |
| // { dg-options "-std=gnu++2a" } |
| // { dg-do run { target c++2a } } |
| |
| #include <functional> |
| #include <testsuite_hooks.h> |
| |
| #ifndef __cpp_lib_bind_front |
| # error "Feature test macro for bind_front is missing" |
| #elif __cpp_lib_bind_front < 201902L |
| # error "Feature test macro for bind_front has wrong value" |
| #endif |
| |
| using std::bind_front; |
| using std::is_same_v; |
| using std::is_invocable_v; |
| using std::is_invocable_r_v; |
| |
| void |
| test01() |
| { |
| struct F { void operator()() {} }; |
| |
| // Arguments should be decayed: |
| static_assert(std::is_same_v< |
| decltype(bind_front(std::declval<F>(), std::declval<int>())), |
| decltype(bind_front(std::declval<F&>(), std::declval<int&>())) |
| >); |
| static_assert(std::is_same_v< |
| decltype(bind_front(std::declval<F>(), std::declval<int>())), |
| decltype(bind_front(std::declval<const F&>(), std::declval<const int&>())) |
| >); |
| |
| // Reference wrappers should be handled: |
| static_assert(!std::is_same_v< |
| decltype(bind_front(std::declval<F>(), std::declval<int&>())), |
| decltype(bind_front(std::declval<F>(), std::ref(std::declval<int&>()))) |
| >); |
| static_assert(!std::is_same_v< |
| decltype(bind_front(std::declval<F>(), std::declval<const int&>())), |
| decltype(bind_front(std::declval<F>(), std::cref(std::declval<int&>()))) |
| >); |
| static_assert(!std::is_same_v< |
| decltype(bind_front(std::declval<F>(), std::ref(std::declval<int&>()))), |
| decltype(bind_front(std::declval<F>(), std::cref(std::declval<int&>()))) |
| >); |
| } |
| |
| void |
| test02() |
| { |
| struct quals |
| { |
| bool as_const; |
| bool as_lvalue; |
| }; |
| |
| struct F |
| { |
| quals operator()() & { return { false, true }; } |
| quals operator()() const & { return { true, true }; } |
| quals operator()() && { return { false, false }; } |
| quals operator()() const && { return { true, false }; } |
| }; |
| |
| F f; |
| auto g = bind_front(f); |
| const auto& cg = g; |
| quals q; |
| |
| // constness and value category should be forwarded to the target object: |
| q = g(); |
| VERIFY( ! q.as_const && q.as_lvalue ); |
| q = std::move(g)(); |
| VERIFY( ! q.as_const && ! q.as_lvalue ); |
| q = cg(); |
| VERIFY( q.as_const && q.as_lvalue ); |
| q = std::move(cg)(); |
| VERIFY( q.as_const && ! q.as_lvalue ); |
| } |
| |
| void |
| test03() |
| { |
| struct F |
| { |
| int& operator()(int& i, void*) { return i; } |
| void* operator()(int, void* p) const { return p; } |
| }; |
| |
| int i = 5; |
| void* vp = &vp; // arbitrary void* value |
| |
| auto g1 = bind_front(F{}, i); // call wrapper has bound arg of type int |
| using G1 = decltype(g1); |
| // Invoking G1& will pass g1's bound arg as int&, so calls first overload: |
| static_assert(is_invocable_r_v<int&, G1&, void*>); |
| // Invoking const G1& or G&& calls second overload: |
| static_assert(is_invocable_r_v<void*, const G1&, void*>); |
| static_assert(is_invocable_r_v<void*, G1&&, void*>); |
| void* p1 = static_cast<G1&&>(g1)(vp); |
| VERIFY( p1 == vp ); |
| |
| auto g2 = bind_front(F{}, std::ref(i)); // bound arg of type int& |
| using G2 = decltype(g2); |
| // Bound arg always forwarded as int& even from G2&& or const G2& |
| static_assert(is_invocable_r_v<int&, G2&, void*>); |
| static_assert(is_invocable_r_v<int&, G2&&, void*>); |
| // But cannot call first overload on const G2: |
| static_assert(is_invocable_r_v<void*, const G2&, void*>); |
| static_assert(is_invocable_r_v<void*, const G2&&, void*>); |
| int& i2 = g2(vp); |
| VERIFY( &i2 == &i ); |
| int& i2r = static_cast<G2&&>(g2)(vp); |
| VERIFY( &i2r == &i ); |
| void* p2 = const_cast<const G2&>(g2)(vp); |
| VERIFY( p2 == vp ); |
| |
| auto g3 = bind_front(F{}, std::cref(i)); // bound arg of type const int& |
| using G3 = decltype(g3); |
| // Bound arg always forwarded as const int& so can only call second overload: |
| static_assert(is_invocable_r_v<void*, G3&, void*>); |
| static_assert(is_invocable_r_v<void*, G3&&, void*>); |
| static_assert(is_invocable_r_v<void*, const G3&, void*>); |
| static_assert(is_invocable_r_v<void*, const G3&&, void*>); |
| |
| auto g4 = bind_front(g2, nullptr); |
| using G4 = decltype(g4); |
| static_assert(is_invocable_r_v<int&, G4&>); |
| static_assert(is_invocable_r_v<int&, G4&&>); |
| static_assert(is_invocable_r_v<void*, const G4&>); |
| static_assert(is_invocable_r_v<void*, const G4&&>); |
| } |
| |
| int f(int i, int j, int k) { return i + j + k; } |
| |
| void |
| test04() |
| { |
| auto g = bind_front(f); |
| VERIFY( g(1, 2, 3) == 6 ); |
| auto g1 = bind_front(f, 1); |
| VERIFY( g1(2, 3) == 6 ); |
| VERIFY( bind_front(g, 1)(2, 3) == 6 ); |
| auto g2 = bind_front(f, 1, 2); |
| VERIFY( g2(3) == 6 ); |
| VERIFY( bind_front(g1, 2)(3) == 6 ); |
| auto g3 = bind_front(f, 1, 2, 3); |
| VERIFY( g3() == 6 ); |
| VERIFY( bind_front(g2, 3)() == 6 ); |
| } |
| |
| int |
| main() |
| { |
| test01(); |
| test02(); |
| test03(); |
| test04(); |
| } |