[libcxx-commits] [libcxx] [libc++] Implement `bind_back` (PR #81055)

via libcxx-commits libcxx-commits at lists.llvm.org
Wed Feb 7 15:42:05 PST 2024


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-libcxx

Author: Jakub Mazurkiewicz (JMazurkiewicz)

<details>
<summary>Changes</summary>

* Partially implement P2387R3: "Pipe support for user-defined range adaptors"
* Refactor `bind_front` tests
* Add `types.h` header with common types for `bind_(front|back)` tests
* Fix value of `__cpp_lib_bind_front` FTM in C++26 mode

---

Patch is 43.54 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/81055.diff


15 Files Affected:

- (modified) libcxx/docs/FeatureTestMacroTable.rst (+1-5) 
- (modified) libcxx/docs/Status/Cxx23.rst (+1) 
- (modified) libcxx/docs/Status/Cxx23Papers.csv (+1-1) 
- (modified) libcxx/include/__functional/bind_back.h (+14) 
- (modified) libcxx/include/functional (+6) 
- (modified) libcxx/include/version (+3-9) 
- (modified) libcxx/test/std/language.support/support.limits/support.limits.general/functional.version.compile.pass.cpp (+12-26) 
- (modified) libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp (+12-26) 
- (added) libcxx/test/std/utilities/function.objects/func.bind.partial/bind_back.pass.cpp (+356) 
- (added) libcxx/test/std/utilities/function.objects/func.bind.partial/bind_back.verify.cpp (+32) 
- (renamed) libcxx/test/std/utilities/function.objects/func.bind.partial/bind_front.pass.cpp (+39-88) 
- (added) libcxx/test/std/utilities/function.objects/func.bind.partial/bind_front.verify.cpp (+32) 
- (added) libcxx/test/std/utilities/function.objects/func.bind.partial/types.h (+74) 
- (removed) libcxx/test/std/utilities/function.objects/func.bind_front/bind_front.verify.cpp (-45) 
- (modified) libcxx/utils/generate_feature_test_macro_components.py (+2-3) 


``````````diff
diff --git a/libcxx/docs/FeatureTestMacroTable.rst b/libcxx/docs/FeatureTestMacroTable.rst
index a5c6fa22cec06c..a3be1b9e71fc3f 100644
--- a/libcxx/docs/FeatureTestMacroTable.rst
+++ b/libcxx/docs/FeatureTestMacroTable.rst
@@ -308,7 +308,7 @@ Status
     --------------------------------------------------- -----------------
     ``__cpp_lib_associative_heterogeneous_erasure``     *unimplemented*
     --------------------------------------------------- -----------------
-    ``__cpp_lib_bind_back``                             *unimplemented*
+    ``__cpp_lib_bind_back``                             ``202202L``
     --------------------------------------------------- -----------------
     ``__cpp_lib_byteswap``                              ``202110L``
     --------------------------------------------------- -----------------
@@ -392,10 +392,6 @@ Status
     ---------------------------------------------------------------------
     ``__cpp_lib_associative_heterogeneous_insertion``   *unimplemented*
     --------------------------------------------------- -----------------
-    ``__cpp_lib_bind_back``                             *unimplemented*
-    --------------------------------------------------- -----------------
-    ``__cpp_lib_bind_front``                            ``202306L``
-    --------------------------------------------------- -----------------
     ``__cpp_lib_bitset``                                ``202306L``
     --------------------------------------------------- -----------------
     ``__cpp_lib_copyable_function``                     *unimplemented*
diff --git a/libcxx/docs/Status/Cxx23.rst b/libcxx/docs/Status/Cxx23.rst
index 3e6e33f08c7ccf..a3a0d8b81e88f9 100644
--- a/libcxx/docs/Status/Cxx23.rst
+++ b/libcxx/docs/Status/Cxx23.rst
@@ -43,6 +43,7 @@ Paper Status
    .. [#note-P0533R9] P0533R9: ``isfinite``, ``isinf``, ``isnan`` and ``isnormal`` are implemented.
    .. [#note-P1413R3] P1413R3: ``std::aligned_storage_t`` and ``std::aligned_union_t`` are marked deprecated, but
       clang doesn't issue a diagnostic for deprecated using template declarations.
+   .. [#note-P2387R3] P2387R3: ``bind_back`` only
    .. [#note-P2520R0] P2520R0: Libc++ implemented this paper as a DR in C++20 as well.
    .. [#note-P2711R1] P2711R1: ``join_with_view`` hasn't been done yet since this type isn't implemented yet.
    .. [#note-P2770R0] P2770R0: ``join_with_view`` hasn't been done yet since this type isn't implemented yet.
diff --git a/libcxx/docs/Status/Cxx23Papers.csv b/libcxx/docs/Status/Cxx23Papers.csv
index eb415ed8c031fa..aebc2ffe5b067a 100644
--- a/libcxx/docs/Status/Cxx23Papers.csv
+++ b/libcxx/docs/Status/Cxx23Papers.csv
@@ -45,7 +45,7 @@
 "`P1413R3 <https://wg21.link/P1413R3>`__","LWG","Deprecate ``std::aligned_storage`` and ``std::aligned_union``","February 2022","|Complete| [#note-P1413R3]_",""
 "`P2255R2 <https://wg21.link/P2255R2>`__","LWG","A type trait to detect reference binding to temporary","February 2022","",""
 "`P2273R3 <https://wg21.link/P2273R3>`__","LWG","Making ``std::unique_ptr`` constexpr","February 2022","|Complete|","16.0"
-"`P2387R3 <https://wg21.link/P2387R3>`__","LWG","Pipe support for user-defined range adaptors","February 2022","","","|ranges|"
+"`P2387R3 <https://wg21.link/P2387R3>`__","LWG","Pipe support for user-defined range adaptors","February 2022","|Partial| [#note-P2387R3]_","","|ranges|"
 "`P2440R1 <https://wg21.link/P2440R1>`__","LWG","``ranges::iota``, ``ranges::shift_left`` and ``ranges::shift_right``","February 2022","","","|ranges|"
 "`P2441R2 <https://wg21.link/P2441R2>`__","LWG","``views::join_with``","February 2022","|In Progress|","","|ranges|"
 "`P2442R1 <https://wg21.link/P2442R1>`__","LWG","Windowing range adaptors: ``views::chunk`` and ``views::slide``","February 2022","","","|ranges|"
diff --git a/libcxx/include/__functional/bind_back.h b/libcxx/include/__functional/bind_back.h
index ce26d3b70630f3..2baab3e252d3d1 100644
--- a/libcxx/include/__functional/bind_back.h
+++ b/libcxx/include/__functional/bind_back.h
@@ -62,6 +62,20 @@ _LIBCPP_HIDE_FROM_ABI constexpr auto __bind_back(_Fn&& __f, _Args&&... __args) n
       std::forward<_Fn>(__f), std::forward_as_tuple(std::forward<_Args>(__args)...));
 }
 
+#  if _LIBCPP_STD_VER >= 23
+template <class _Fn, class... _Args>
+  requires is_constructible_v<decay_t<_Fn>, _Fn> && is_move_constructible_v<decay_t<_Fn>> &&
+           (is_constructible_v<decay_t<_Args>, _Args> && ...) && (is_move_constructible_v<decay_t<_Args>> && ...)
+_LIBCPP_HIDE_FROM_ABI constexpr auto bind_back(_Fn&& __f, _Args&&... __args) noexcept(
+    noexcept(__bind_back_t<decay_t<_Fn>, tuple<decay_t<_Args>...>>(
+        std::forward<_Fn>(__f), std::forward_as_tuple(std::forward<_Args>(__args)...))))
+    -> decltype(__bind_back_t<decay_t<_Fn>, tuple<decay_t<_Args>...>>(
+        std::forward<_Fn>(__f), std::forward_as_tuple(std::forward<_Args>(__args)...))) {
+  return __bind_back_t<decay_t<_Fn>, tuple<decay_t<_Args>...>>(
+      std::forward<_Fn>(__f), std::forward_as_tuple(std::forward<_Args>(__args)...));
+}
+#  endif // _LIBCPP_STD_VER >= 20
+
 #endif // _LIBCPP_STD_VER >= 20
 
 _LIBCPP_END_NAMESPACE_STD
diff --git a/libcxx/include/functional b/libcxx/include/functional
index fd99e11fb18180..d72ebb2310c5ae 100644
--- a/libcxx/include/functional
+++ b/libcxx/include/functional
@@ -207,6 +207,12 @@ binary_negate<Predicate> not2(const Predicate& pred);
 template <class F>
 constexpr unspecified not_fn(F&& f); // C++17, constexpr in C++20
 
+// [func.bind.partial], function templates bind_front and bind_back
+template<class F, class... Args>
+  constexpr unspecified bind_front(F&&, Args&&...); // C++20
+template<class F, class... Args>
+  constexpr unspecified bind_back(F&&, Args&&...);  // C++23
+
 template<class T> struct is_bind_expression;
 template<class T> struct is_placeholder;
 
diff --git a/libcxx/include/version b/libcxx/include/version
index b18927a2bc38c2..5dc73becc943c6 100644
--- a/libcxx/include/version
+++ b/libcxx/include/version
@@ -40,10 +40,8 @@ __cpp_lib_atomic_shared_ptr                             201711L <atomic>
 __cpp_lib_atomic_value_initialization                   201911L <atomic> <memory>
 __cpp_lib_atomic_wait                                   201907L <atomic>
 __cpp_lib_barrier                                       201907L <barrier>
-__cpp_lib_bind_back                                     202306L <functional>
-                                                        202202L // C++23
-__cpp_lib_bind_front                                    202306L <functional>
-                                                        201907L // C++20
+__cpp_lib_bind_back                                     202202L <functional>
+__cpp_lib_bind_front                                    201907L <functional>
 __cpp_lib_bit_cast                                      201806L <bit>
 __cpp_lib_bitops                                        201907L <bit>
 __cpp_lib_bitset                                        202306L <bitset>
@@ -439,7 +437,7 @@ __cpp_lib_within_lifetime                               202306L <type_traits>
 # define __cpp_lib_adaptor_iterator_pair_constructor    202106L
 # define __cpp_lib_allocate_at_least                    202302L
 // # define __cpp_lib_associative_heterogeneous_erasure    202110L
-// # define __cpp_lib_bind_back                            202202L
+# define __cpp_lib_bind_back                            202202L
 # define __cpp_lib_byteswap                             202110L
 # define __cpp_lib_constexpr_bitset                     202207L
 # define __cpp_lib_constexpr_charconv                   202207L
@@ -485,10 +483,6 @@ __cpp_lib_within_lifetime                               202306L <type_traits>
 
 #if _LIBCPP_STD_VER >= 26
 // # define __cpp_lib_associative_heterogeneous_insertion  202306L
-# undef  __cpp_lib_bind_back
-// # define __cpp_lib_bind_back                            202306L
-# undef  __cpp_lib_bind_front
-# define __cpp_lib_bind_front                           202306L
 # define __cpp_lib_bitset                               202306L
 // # define __cpp_lib_copyable_function                    202306L
 // # define __cpp_lib_debugging                            202311L
diff --git a/libcxx/test/std/language.support/support.limits/support.limits.general/functional.version.compile.pass.cpp b/libcxx/test/std/language.support/support.limits/support.limits.general/functional.version.compile.pass.cpp
index 72c96c62b64c45..db4c183544caa2 100644
--- a/libcxx/test/std/language.support/support.limits/support.limits.general/functional.version.compile.pass.cpp
+++ b/libcxx/test/std/language.support/support.limits/support.limits.general/functional.version.compile.pass.cpp
@@ -17,9 +17,7 @@
 
 /*  Constant                           Value
     __cpp_lib_bind_back                202202L [C++23]
-                                       202306L [C++26]
     __cpp_lib_bind_front               201907L [C++20]
-                                       202306L [C++26]
     __cpp_lib_boyer_moore_searcher     201603L [C++17]
     __cpp_lib_constexpr_functional     201907L [C++20]
     __cpp_lib_copyable_function        202306L [C++26]
@@ -320,17 +318,11 @@
 
 #elif TEST_STD_VER == 23
 
-# if !defined(_LIBCPP_VERSION)
-#   ifndef __cpp_lib_bind_back
-#     error "__cpp_lib_bind_back should be defined in c++23"
-#   endif
-#   if __cpp_lib_bind_back != 202202L
-#     error "__cpp_lib_bind_back should have the value 202202L in c++23"
-#   endif
-# else // _LIBCPP_VERSION
-#   ifdef __cpp_lib_bind_back
-#     error "__cpp_lib_bind_back should not be defined because it is unimplemented in libc++!"
-#   endif
+# ifndef __cpp_lib_bind_back
+#   error "__cpp_lib_bind_back should be defined in c++23"
+# endif
+# if __cpp_lib_bind_back != 202202L
+#   error "__cpp_lib_bind_back should have the value 202202L in c++23"
 # endif
 
 # ifndef __cpp_lib_bind_front
@@ -426,24 +418,18 @@
 
 #elif TEST_STD_VER > 23
 
-# if !defined(_LIBCPP_VERSION)
-#   ifndef __cpp_lib_bind_back
-#     error "__cpp_lib_bind_back should be defined in c++26"
-#   endif
-#   if __cpp_lib_bind_back != 202306L
-#     error "__cpp_lib_bind_back should have the value 202306L in c++26"
-#   endif
-# else // _LIBCPP_VERSION
-#   ifdef __cpp_lib_bind_back
-#     error "__cpp_lib_bind_back should not be defined because it is unimplemented in libc++!"
-#   endif
+# ifndef __cpp_lib_bind_back
+#   error "__cpp_lib_bind_back should be defined in c++26"
+# endif
+# if __cpp_lib_bind_back != 202202L
+#   error "__cpp_lib_bind_back should have the value 202202L in c++26"
 # endif
 
 # ifndef __cpp_lib_bind_front
 #   error "__cpp_lib_bind_front should be defined in c++26"
 # endif
-# if __cpp_lib_bind_front != 202306L
-#   error "__cpp_lib_bind_front should have the value 202306L in c++26"
+# if __cpp_lib_bind_front != 201907L
+#   error "__cpp_lib_bind_front should have the value 201907L in c++26"
 # endif
 
 # ifndef __cpp_lib_boyer_moore_searcher
diff --git a/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp b/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp
index 14271308624e65..18aaadaeacc4ea 100644
--- a/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp
+++ b/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp
@@ -38,9 +38,7 @@
     __cpp_lib_atomic_wait                            201907L [C++20]
     __cpp_lib_barrier                                201907L [C++20]
     __cpp_lib_bind_back                              202202L [C++23]
-                                                     202306L [C++26]
     __cpp_lib_bind_front                             201907L [C++20]
-                                                     202306L [C++26]
     __cpp_lib_bit_cast                               201806L [C++20]
     __cpp_lib_bitops                                 201907L [C++20]
     __cpp_lib_bitset                                 202306L [C++26]
@@ -4465,17 +4463,11 @@
 #   endif
 # endif
 
-# if !defined(_LIBCPP_VERSION)
-#   ifndef __cpp_lib_bind_back
-#     error "__cpp_lib_bind_back should be defined in c++23"
-#   endif
-#   if __cpp_lib_bind_back != 202202L
-#     error "__cpp_lib_bind_back should have the value 202202L in c++23"
-#   endif
-# else // _LIBCPP_VERSION
-#   ifdef __cpp_lib_bind_back
-#     error "__cpp_lib_bind_back should not be defined because it is unimplemented in libc++!"
-#   endif
+# ifndef __cpp_lib_bind_back
+#   error "__cpp_lib_bind_back should be defined in c++23"
+# endif
+# if __cpp_lib_bind_back != 202202L
+#   error "__cpp_lib_bind_back should have the value 202202L in c++23"
 # endif
 
 # ifndef __cpp_lib_bind_front
@@ -6053,24 +6045,18 @@
 #   endif
 # endif
 
-# if !defined(_LIBCPP_VERSION)
-#   ifndef __cpp_lib_bind_back
-#     error "__cpp_lib_bind_back should be defined in c++26"
-#   endif
-#   if __cpp_lib_bind_back != 202306L
-#     error "__cpp_lib_bind_back should have the value 202306L in c++26"
-#   endif
-# else // _LIBCPP_VERSION
-#   ifdef __cpp_lib_bind_back
-#     error "__cpp_lib_bind_back should not be defined because it is unimplemented in libc++!"
-#   endif
+# ifndef __cpp_lib_bind_back
+#   error "__cpp_lib_bind_back should be defined in c++26"
+# endif
+# if __cpp_lib_bind_back != 202202L
+#   error "__cpp_lib_bind_back should have the value 202202L in c++26"
 # endif
 
 # ifndef __cpp_lib_bind_front
 #   error "__cpp_lib_bind_front should be defined in c++26"
 # endif
-# if __cpp_lib_bind_front != 202306L
-#   error "__cpp_lib_bind_front should have the value 202306L in c++26"
+# if __cpp_lib_bind_front != 201907L
+#   error "__cpp_lib_bind_front should have the value 201907L in c++26"
 # endif
 
 # ifndef __cpp_lib_bit_cast
diff --git a/libcxx/test/std/utilities/function.objects/func.bind.partial/bind_back.pass.cpp b/libcxx/test/std/utilities/function.objects/func.bind.partial/bind_back.pass.cpp
new file mode 100644
index 00000000000000..aac1bd63a54cbe
--- /dev/null
+++ b/libcxx/test/std/utilities/function.objects/func.bind.partial/bind_back.pass.cpp
@@ -0,0 +1,356 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
+
+// <functional>
+
+// template<class F, class... Args>
+//   constexpr unspecified bind_back(F&& f, Args&&... args);
+
+#include <functional>
+
+#include <cassert>
+#include <tuple>
+#include <utility>
+
+#include "callable_types.h"
+#include "types.h"
+
+template <class Fn, class... Args>
+concept back_bindable =
+    requires(Fn&& fn, Args&&... args) { std::bind_back(std::forward<Fn>(fn), std::forward<Args>(args)...); };
+
+constexpr bool test() {
+  // Bind arguments, call without arguments
+  {
+    {
+      auto f = std::bind_back(MakeTuple{});
+      assert(f() == std::make_tuple());
+    }
+    {
+      auto f = std::bind_back(MakeTuple{}, Elem<1>{});
+      assert(f() == std::make_tuple(Elem<1>{}));
+    }
+    {
+      auto f = std::bind_back(MakeTuple{}, Elem<1>{}, Elem<2>{});
+      assert(f() == std::make_tuple(Elem<1>{}, Elem<2>{}));
+    }
+    {
+      auto f = std::bind_back(MakeTuple{}, Elem<1>{}, Elem<2>{}, Elem<3>{});
+      assert(f() == std::make_tuple(Elem<1>{}, Elem<2>{}, Elem<3>{}));
+    }
+  }
+
+  // Bind no arguments, call with arguments
+  {
+    {
+      auto f = std::bind_back(MakeTuple{});
+      assert(f(Elem<1>{}) == std::make_tuple(Elem<1>{}));
+    }
+    {
+      auto f = std::bind_back(MakeTuple{});
+      assert(f(Elem<1>{}, Elem<2>{}) == std::make_tuple(Elem<1>{}, Elem<2>{}));
+    }
+    {
+      auto f = std::bind_back(MakeTuple{});
+      assert(f(Elem<1>{}, Elem<2>{}, Elem<3>{}) == std::make_tuple(Elem<1>{}, Elem<2>{}, Elem<3>{}));
+    }
+  }
+
+  // Bind arguments, call with arguments
+  {
+    {
+      auto f = std::bind_back(MakeTuple{}, Elem<1>{});
+      assert(f(Elem<10>{}) == std::make_tuple(Elem<10>{}, Elem<1>{}));
+    }
+    {
+      auto f = std::bind_back(MakeTuple{}, Elem<1>{}, Elem<2>{});
+      assert(f(Elem<10>{}) == std::make_tuple(Elem<10>{}, Elem<1>{}, Elem<2>{}));
+    }
+    {
+      auto f = std::bind_back(MakeTuple{}, Elem<1>{}, Elem<2>{}, Elem<3>{});
+      assert(f(Elem<10>{}) == std::make_tuple(Elem<10>{}, Elem<1>{}, Elem<2>{}, Elem<3>{}));
+    }
+
+    {
+      auto f = std::bind_back(MakeTuple{}, Elem<1>{});
+      assert(f(Elem<10>{}, Elem<11>{}) == std::make_tuple(Elem<10>{}, Elem<11>{}, Elem<1>{}));
+    }
+    {
+      auto f = std::bind_back(MakeTuple{}, Elem<1>{}, Elem<2>{});
+      assert(f(Elem<10>{}, Elem<11>{}) == std::make_tuple(Elem<10>{}, Elem<11>{}, Elem<1>{}, Elem<2>{}));
+    }
+    {
+      auto f = std::bind_back(MakeTuple{}, Elem<1>{}, Elem<2>{}, Elem<3>{});
+      assert(f(Elem<10>{}, Elem<11>{}) == std::make_tuple(Elem<10>{}, Elem<11>{}, Elem<1>{}, Elem<2>{}, Elem<3>{}));
+    }
+  }
+
+  // Basic tests with fundamental types
+  {
+    int n     = 2;
+    int m     = 1;
+    auto add  = [](int x, int y) { return x + y; };
+    auto addN = [](int a, int b, int c, int d, int e, int f) { return a + b + c + d + e + f; };
+
+    auto a = std::bind_back(add, m, n);
+    assert(a() == 3);
+
+    auto b = std::bind_back(addN, m, n, m, m, m, m);
+    assert(b() == 7);
+
+    auto c = std::bind_back(addN, n, m);
+    assert(c(1, 1, 1, 1) == 7);
+
+    auto f = std::bind_back(add, n);
+    assert(f(3) == 5);
+
+    auto g = std::bind_back(add, n, 1);
+    assert(g() == 3);
+
+    auto h = std::bind_back(addN, 1, 1, 1);
+    assert(h(2, 2, 2) == 9);
+  }
+
+  // Make sure we don't treat std::reference_wrapper specially.
+  {
+    auto sub = [](std::reference_wrapper<int> a, std::reference_wrapper<int> b) { return a.get() - b.get(); };
+    int i = 1, j = 2;
+    auto f = std::bind_back(sub, std::ref(i));
+    assert(f(std::ref(j)) == 2 - 1);
+  }
+
+  // Make sure we can call a function that's a pointer to a member function.
+  {
+    struct MemberFunction {
+      constexpr bool foo(int, int) { return true; }
+    };
+    MemberFunction value;
+    auto fn = std::bind_back(&MemberFunction::foo, 0, 0);
+    assert(fn(value));
+  }
+
+  // Make sure that we copy the bound arguments into the unspecified-type.
+  {
+    auto add = [](int x, int y) { return x + y; };
+    int n    = 2;
+    auto i   = std::bind_back(add, n, 1);
+    n        = 100;
+    assert(i() == 3);
+  }
+
+  // Make sure we pass the bound arguments to the function object
+  // with the right value category.
+  {
+    {
+      auto wasCopied = [](CopyMoveInfo info) { return info.copy_kind == CopyMoveInfo::copy; };
+      CopyMoveInfo info;
+      auto copied = std::bind_back(wasCopied, info);
+      assert(copied());
+    }
+
+    {
+      auto wasMoved = [](CopyMoveInfo info) { return info.copy_kind == CopyMoveInfo::move; };
+      CopyMoveInfo info;
+      auto moved = std::bind_back(wasMoved, info);
+      assert(std::move(moved)());
+    }
+  }
+
+  // Make sure we call the correctly cv-ref qualified operator() based on the
+  // value category of the bind_back unspecified-type.
+  {
+    struct F {
+      constexpr int operator()() & { return 1; }
+      constexpr int operator()() const& { return 2; }
+      constexpr int operator()() && { return 3; }
+      constexpr int operator()() const&& { return 4; }
+    };
+    auto x  = std::bind_back(F{});
+    using X = decltype(x);
+    assert(static_cast<X&>(x)() == 1);
+    assert(static_cast<X const&>(x)() == 2);
+    assert(static_cast<X&&>(x)() == 3);
+    assert(static_cast<X const&&>(x)() == 4);
+  }
+
+  // Make sure the bind_back unspecified-type is NOT invocable when the call would select a
+  // differently-qualified operator().
+  //
+  // For example, if the call to `operator()() &` is ill-formed, the call to the unspecified-type
+  // should be ill-formed and not fall back to the `operator()() const&` overload.
+  { // Make sure we delete the & overload when the underlying call isn't valid
+    {
+      struct F {
+        void operator()() & = delete;
+    ...
[truncated]

``````````

</details>


https://github.com/llvm/llvm-project/pull/81055


More information about the libcxx-commits mailing list