[libcxx-commits] [libcxx] 3ec6c99 - [libc++] Implement P1169R4 (static operator())

Nikolas Klauser via libcxx-commits libcxx-commits at lists.llvm.org
Wed Dec 14 17:19:00 PST 2022


Author: Nikolas Klauser
Date: 2022-12-15T02:18:54+01:00
New Revision: 3ec6c997c67d685c533b8c9c2cffde31d834b821

URL: https://github.com/llvm/llvm-project/commit/3ec6c997c67d685c533b8c9c2cffde31d834b821
DIFF: https://github.com/llvm/llvm-project/commit/3ec6c997c67d685c533b8c9c2cffde31d834b821.diff

LOG: [libc++] Implement P1169R4 (static operator())

Reviewed By: ldionne, huixie90, #libc

Spies: EricWF, libcxx-commits, royjacobson

Differential Revision: https://reviews.llvm.org/D135016

Added: 
    libcxx/include/__type_traits/strip_signature.h
    libcxx/test/std/thread/futures/futures.task/futures.task.members/ctad.compile.pass.cpp
    libcxx/test/std/thread/futures/futures.task/futures.task.members/ctad.static.compile.pass.cpp
    libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.func/func.wrap.func.con/ctad.static.compile.pass.cpp

Modified: 
    libcxx/docs/ReleaseNotes.rst
    libcxx/docs/Status/Cxx2bIssues.csv
    libcxx/docs/Status/Cxx2bPapers.csv
    libcxx/include/CMakeLists.txt
    libcxx/include/__functional/function.h
    libcxx/include/future
    libcxx/include/module.modulemap.in
    libcxx/test/libcxx/private_headers.verify.cpp

Removed: 
    


################################################################################
diff  --git a/libcxx/docs/ReleaseNotes.rst b/libcxx/docs/ReleaseNotes.rst
index 2b16ec5475259..3929be5c459ad 100644
--- a/libcxx/docs/ReleaseNotes.rst
+++ b/libcxx/docs/ReleaseNotes.rst
@@ -49,6 +49,7 @@ Implemented Papers
 - P2438R2 - ``std::string::substr() &&``
 - P0600R1 - ``nodiscard`` in the library
 - P0339R6 - ``polymorphic_allocator<>`` as a vocabulary type
+- P1169R4 - ``static operator()``
 
 Improvements and New Features
 -----------------------------

diff  --git a/libcxx/docs/Status/Cxx2bIssues.csv b/libcxx/docs/Status/Cxx2bIssues.csv
index 67f46373029e0..756c6869fed24 100644
--- a/libcxx/docs/Status/Cxx2bIssues.csv
+++ b/libcxx/docs/Status/Cxx2bIssues.csv
@@ -1,6 +1,6 @@
 "Issue #","Issue Name","Meeting","Status","First released version","Labels"
 "`2839 <https://wg21.link/LWG2839>`__","Self-move-assignment of library types, again","November 2020","|Nothing To Do|",""
-"`3117 <https://wg21.link/LWG3117>`__","Missing ``packaged_task`` deduction guides","November 2020","",""
+"`3117 <https://wg21.link/LWG3117>`__","Missing ``packaged_task`` deduction guides","November 2020","|Complete|","16.0"
 "`3143 <https://wg21.link/LWG3143>`__","``monotonic_buffer_resource`` growth policy is unclear","November 2020","",""
 "`3195 <https://wg21.link/LWG3195>`__","What is the stored pointer value of an empty ``weak_ptr``?","November 2020","|Nothing To Do|",""
 "`3211 <https://wg21.link/LWG3211>`__","``std::tuple<>`` should be trivially constructible","November 2020","|Complete|","9.0"

diff  --git a/libcxx/docs/Status/Cxx2bPapers.csv b/libcxx/docs/Status/Cxx2bPapers.csv
index e6245261a7d0a..9c98e15c1a7cf 100644
--- a/libcxx/docs/Status/Cxx2bPapers.csv
+++ b/libcxx/docs/Status/Cxx2bPapers.csv
@@ -53,7 +53,7 @@
 "","","","","",""
 "`P0009R18 <https://wg21.link/P0009R18>`__","LWG","mdspan: A Non-Owning Multidimensional Array Reference","July 2022","",""
 "`P0429R9 <https://wg21.link/P0429R9>`__","LWG","A Standard ``flat_map``","July 2022","",""
-"`P1169R4 <https://wg21.link/P1169R4>`__","LWG","``static operator()``","July 2022","",""
+"`P1169R4 <https://wg21.link/P1169R4>`__","LWG","``static operator()``","July 2022","|Complete|","16.0"
 "`P1222R4 <https://wg21.link/P1222R4>`__","LWG","A Standard ``flat_set``","July 2022","",""
 "`P1223R5 <https://wg21.link/P1223R5>`__","LWG","``ranges::find_last()``, ``ranges::find_last_if()``, and ``ranges::find_last_if_not()``","July 2022","","","|ranges|"
 "`P1467R9 <https://wg21.link/P1467R9>`__","LWG","Extended ``floating-point`` types and standard names","July 2022","",""

diff  --git a/libcxx/include/CMakeLists.txt b/libcxx/include/CMakeLists.txt
index 1c8ce896ada50..62fa8d96d0600 100644
--- a/libcxx/include/CMakeLists.txt
+++ b/libcxx/include/CMakeLists.txt
@@ -672,6 +672,7 @@ set(files
   __type_traits/remove_reference.h
   __type_traits/remove_volatile.h
   __type_traits/result_of.h
+  __type_traits/strip_signature.h
   __type_traits/type_identity.h
   __type_traits/type_list.h
   __type_traits/underlying_type.h

diff  --git a/libcxx/include/__functional/function.h b/libcxx/include/__functional/function.h
index 2d9cdc0459d63..436149e88ae37 100644
--- a/libcxx/include/__functional/function.h
+++ b/libcxx/include/__functional/function.h
@@ -23,6 +23,7 @@
 #include <__memory/builtin_new_allocator.h>
 #include <__memory/compressed_pair.h>
 #include <__memory/unique_ptr.h>
+#include <__type_traits/strip_signature.h>
 #include <__utility/forward.h>
 #include <__utility/move.h>
 #include <__utility/piecewise_construct.h>
@@ -1063,45 +1064,6 @@ class _LIBCPP_TEMPLATE_VIS function<_Rp(_ArgTypes...)>
 template<class _Rp, class ..._Ap>
 function(_Rp(*)(_Ap...)) -> function<_Rp(_Ap...)>;
 
-template<class _Fp>
-struct __strip_signature;
-
-template<class _Rp, class _Gp, class ..._Ap>
-struct __strip_signature<_Rp (_Gp::*) (_Ap...)> { using type = _Rp(_Ap...); };
-template<class _Rp, class _Gp, class ..._Ap>
-struct __strip_signature<_Rp (_Gp::*) (_Ap...) const> { using type = _Rp(_Ap...); };
-template<class _Rp, class _Gp, class ..._Ap>
-struct __strip_signature<_Rp (_Gp::*) (_Ap...) volatile> { using type = _Rp(_Ap...); };
-template<class _Rp, class _Gp, class ..._Ap>
-struct __strip_signature<_Rp (_Gp::*) (_Ap...) const volatile> { using type = _Rp(_Ap...); };
-
-template<class _Rp, class _Gp, class ..._Ap>
-struct __strip_signature<_Rp (_Gp::*) (_Ap...) &> { using type = _Rp(_Ap...); };
-template<class _Rp, class _Gp, class ..._Ap>
-struct __strip_signature<_Rp (_Gp::*) (_Ap...) const &> { using type = _Rp(_Ap...); };
-template<class _Rp, class _Gp, class ..._Ap>
-struct __strip_signature<_Rp (_Gp::*) (_Ap...) volatile &> { using type = _Rp(_Ap...); };
-template<class _Rp, class _Gp, class ..._Ap>
-struct __strip_signature<_Rp (_Gp::*) (_Ap...) const volatile &> { using type = _Rp(_Ap...); };
-
-template<class _Rp, class _Gp, class ..._Ap>
-struct __strip_signature<_Rp (_Gp::*) (_Ap...) noexcept> { using type = _Rp(_Ap...); };
-template<class _Rp, class _Gp, class ..._Ap>
-struct __strip_signature<_Rp (_Gp::*) (_Ap...) const noexcept> { using type = _Rp(_Ap...); };
-template<class _Rp, class _Gp, class ..._Ap>
-struct __strip_signature<_Rp (_Gp::*) (_Ap...) volatile noexcept> { using type = _Rp(_Ap...); };
-template<class _Rp, class _Gp, class ..._Ap>
-struct __strip_signature<_Rp (_Gp::*) (_Ap...) const volatile noexcept> { using type = _Rp(_Ap...); };
-
-template<class _Rp, class _Gp, class ..._Ap>
-struct __strip_signature<_Rp (_Gp::*) (_Ap...) & noexcept> { using type = _Rp(_Ap...); };
-template<class _Rp, class _Gp, class ..._Ap>
-struct __strip_signature<_Rp (_Gp::*) (_Ap...) const & noexcept> { using type = _Rp(_Ap...); };
-template<class _Rp, class _Gp, class ..._Ap>
-struct __strip_signature<_Rp (_Gp::*) (_Ap...) volatile & noexcept> { using type = _Rp(_Ap...); };
-template<class _Rp, class _Gp, class ..._Ap>
-struct __strip_signature<_Rp (_Gp::*) (_Ap...) const volatile & noexcept> { using type = _Rp(_Ap...); };
-
 template<class _Fp, class _Stripped = typename __strip_signature<decltype(&_Fp::operator())>::type>
 function(_Fp) -> function<_Stripped>;
 #endif // _LIBCPP_STD_VER >= 17

diff  --git a/libcxx/include/__type_traits/strip_signature.h b/libcxx/include/__type_traits/strip_signature.h
new file mode 100644
index 0000000000000..2bb7393c1ee7f
--- /dev/null
+++ b/libcxx/include/__type_traits/strip_signature.h
@@ -0,0 +1,79 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef _LIBCPP___TYPE_TRAITS_STRIP_SIGNATURE_H
+#define _LIBCPP___TYPE_TRAITS_STRIP_SIGNATURE_H
+
+#include <__config>
+
+#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
+#  pragma GCC system_header
+#endif
+
+#if _LIBCPP_STD_VER >= 17
+
+_LIBCPP_BEGIN_NAMESPACE_STD
+
+template<class _Fp>
+struct __strip_signature;
+
+#  if defined(__cpp_static_call_operator) && __cpp_static_call_operator >= 202207L
+
+template <class _Rp, class... _Args>
+struct __strip_signature<_Rp(*)(_Args...)> {
+  using type = _Rp(_Args...);
+};
+
+template <class _Rp, class... _Args>
+struct __strip_signature<_Rp(*)(_Args...) noexcept> {
+  using type = _Rp(_Args...);
+};
+
+#  endif // defined(__cpp_static_call_operator) && __cpp_static_call_operator >= 202207L
+
+template<class _Rp, class _Gp, class ..._Ap>
+struct __strip_signature<_Rp (_Gp::*) (_Ap...)> { using type = _Rp(_Ap...); };
+template<class _Rp, class _Gp, class ..._Ap>
+struct __strip_signature<_Rp (_Gp::*) (_Ap...) const> { using type = _Rp(_Ap...); };
+template<class _Rp, class _Gp, class ..._Ap>
+struct __strip_signature<_Rp (_Gp::*) (_Ap...) volatile> { using type = _Rp(_Ap...); };
+template<class _Rp, class _Gp, class ..._Ap>
+struct __strip_signature<_Rp (_Gp::*) (_Ap...) const volatile> { using type = _Rp(_Ap...); };
+
+template<class _Rp, class _Gp, class ..._Ap>
+struct __strip_signature<_Rp (_Gp::*) (_Ap...) &> { using type = _Rp(_Ap...); };
+template<class _Rp, class _Gp, class ..._Ap>
+struct __strip_signature<_Rp (_Gp::*) (_Ap...) const &> { using type = _Rp(_Ap...); };
+template<class _Rp, class _Gp, class ..._Ap>
+struct __strip_signature<_Rp (_Gp::*) (_Ap...) volatile &> { using type = _Rp(_Ap...); };
+template<class _Rp, class _Gp, class ..._Ap>
+struct __strip_signature<_Rp (_Gp::*) (_Ap...) const volatile &> { using type = _Rp(_Ap...); };
+
+template<class _Rp, class _Gp, class ..._Ap>
+struct __strip_signature<_Rp (_Gp::*) (_Ap...) noexcept> { using type = _Rp(_Ap...); };
+template<class _Rp, class _Gp, class ..._Ap>
+struct __strip_signature<_Rp (_Gp::*) (_Ap...) const noexcept> { using type = _Rp(_Ap...); };
+template<class _Rp, class _Gp, class ..._Ap>
+struct __strip_signature<_Rp (_Gp::*) (_Ap...) volatile noexcept> { using type = _Rp(_Ap...); };
+template<class _Rp, class _Gp, class ..._Ap>
+struct __strip_signature<_Rp (_Gp::*) (_Ap...) const volatile noexcept> { using type = _Rp(_Ap...); };
+
+template<class _Rp, class _Gp, class ..._Ap>
+struct __strip_signature<_Rp (_Gp::*) (_Ap...) & noexcept> { using type = _Rp(_Ap...); };
+template<class _Rp, class _Gp, class ..._Ap>
+struct __strip_signature<_Rp (_Gp::*) (_Ap...) const & noexcept> { using type = _Rp(_Ap...); };
+template<class _Rp, class _Gp, class ..._Ap>
+struct __strip_signature<_Rp (_Gp::*) (_Ap...) volatile & noexcept> { using type = _Rp(_Ap...); };
+template<class _Rp, class _Gp, class ..._Ap>
+struct __strip_signature<_Rp (_Gp::*) (_Ap...) const volatile & noexcept> { using type = _Rp(_Ap...); };
+
+_LIBCPP_END_NAMESPACE_STD
+
+#endif // _LIBCPP_STD_VER >= 17
+
+#endif // _LIBCPP___TYPE_TRAITS_STRIP_SIGNATURE_H

diff  --git a/libcxx/include/future b/libcxx/include/future
index e317e8d636ef7..a5c1a7bc5cfb1 100644
--- a/libcxx/include/future
+++ b/libcxx/include/future
@@ -369,6 +369,7 @@ template <class R, class Alloc> struct uses_allocator<packaged_task<R>, Alloc>;
 #include <__memory/allocator_arg_t.h>
 #include <__memory/allocator_destructor.h>
 #include <__memory/uses_allocator.h>
+#include <__type_traits/strip_signature.h>
 #include <__utility/auto_cast.h>
 #include <__utility/forward.h>
 #include <__utility/move.h>
@@ -2050,6 +2051,16 @@ public:
     void reset();
 };
 
+#if _LIBCPP_STD_VER >= 17
+
+template <class _Rp, class... _Args>
+packaged_task(_Rp(*)(_Args...)) -> packaged_task<_Rp(_Args...)>;
+
+template <class _Fp, class _Stripped = typename __strip_signature<decltype(&_Fp::operator())>::type>
+packaged_task(_Fp) -> packaged_task<_Stripped>;
+
+#endif
+
 template<class ..._ArgTypes>
 void
 packaged_task<void(_ArgTypes...)>::operator()(_ArgTypes... __args)

diff  --git a/libcxx/include/module.modulemap.in b/libcxx/include/module.modulemap.in
index e6481a823e9b3..4c3a09d1a5f00 100644
--- a/libcxx/include/module.modulemap.in
+++ b/libcxx/include/module.modulemap.in
@@ -1482,6 +1482,7 @@ module std [system] {
     module remove_reference                    { private header "__type_traits/remove_reference.h" }
     module remove_volatile                     { private header "__type_traits/remove_volatile.h" }
     module result_of                           { private header "__type_traits/result_of.h" }
+    module strip_signature                     { private header "__type_traits/strip_signature.h" }
     module type_identity                       { private header "__type_traits/type_identity.h" }
     module type_list                           { private header "__type_traits/type_list.h" }
     module underlying_type                     { private header "__type_traits/underlying_type.h" }

diff  --git a/libcxx/test/libcxx/private_headers.verify.cpp b/libcxx/test/libcxx/private_headers.verify.cpp
index 55a0c268a579c..23186a9581971 100644
--- a/libcxx/test/libcxx/private_headers.verify.cpp
+++ b/libcxx/test/libcxx/private_headers.verify.cpp
@@ -685,6 +685,7 @@ END-SCRIPT
 #include <__type_traits/remove_reference.h> // expected-error@*:* {{use of private header from outside its module: '__type_traits/remove_reference.h'}}
 #include <__type_traits/remove_volatile.h> // expected-error@*:* {{use of private header from outside its module: '__type_traits/remove_volatile.h'}}
 #include <__type_traits/result_of.h> // expected-error@*:* {{use of private header from outside its module: '__type_traits/result_of.h'}}
+#include <__type_traits/strip_signature.h> // expected-error@*:* {{use of private header from outside its module: '__type_traits/strip_signature.h'}}
 #include <__type_traits/type_identity.h> // expected-error@*:* {{use of private header from outside its module: '__type_traits/type_identity.h'}}
 #include <__type_traits/type_list.h> // expected-error@*:* {{use of private header from outside its module: '__type_traits/type_list.h'}}
 #include <__type_traits/underlying_type.h> // expected-error@*:* {{use of private header from outside its module: '__type_traits/underlying_type.h'}}

diff  --git a/libcxx/test/std/thread/futures/futures.task/futures.task.members/ctad.compile.pass.cpp b/libcxx/test/std/thread/futures/futures.task/futures.task.members/ctad.compile.pass.cpp
new file mode 100644
index 0000000000000..0389ed8fccf0a
--- /dev/null
+++ b/libcxx/test/std/thread/futures/futures.task/futures.task.members/ctad.compile.pass.cpp
@@ -0,0 +1,77 @@
+//===----------------------------------------------------------------------===//
+//
+// 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: no-threads
+// UNSUPPORTED: c++03, c++11, c++14
+
+// checks that CTAD works properly
+
+#include <future>
+#include <type_traits>
+
+int func(char*);
+static_assert(std::is_same_v<decltype(std::packaged_task{func}), std::packaged_task<int(char*)>>);
+
+int funcn(char*) noexcept;
+static_assert(std::is_same_v<decltype(std::packaged_task{funcn}), std::packaged_task<int(char*)>>);
+
+template <bool Noexcept>
+struct Callable {
+  int operator()(char*) noexcept(Noexcept);
+};
+static_assert(std::is_same_v<decltype(std::packaged_task{Callable<true>{}}), std::packaged_task<int(char*)>>);
+static_assert(std::is_same_v<decltype(std::packaged_task{Callable<false>{}}), std::packaged_task<int(char*)>>);
+
+template <bool Noexcept>
+struct CallableC {
+  int operator()(char*) const noexcept(Noexcept);
+};
+static_assert(std::is_same_v<decltype(std::packaged_task{CallableC<true>{}}), std::packaged_task<int(char*)>>);
+static_assert(std::is_same_v<decltype(std::packaged_task{CallableC<false>{}}), std::packaged_task<int(char*)>>);
+
+template <bool Noexcept>
+struct CallableV {
+  int operator()(char*) const noexcept(Noexcept);
+};
+static_assert(std::is_same_v<decltype(std::packaged_task{CallableV<true>{}}), std::packaged_task<int(char*)>>);
+static_assert(std::is_same_v<decltype(std::packaged_task{CallableV<false>{}}), std::packaged_task<int(char*)>>);
+
+template <bool Noexcept>
+struct CallableCV {
+  int operator()(char*) const volatile noexcept(Noexcept);
+};
+static_assert(std::is_same_v<decltype(std::packaged_task{CallableCV<true>{}}), std::packaged_task<int(char*)>>);
+static_assert(std::is_same_v<decltype(std::packaged_task{CallableCV<false>{}}), std::packaged_task<int(char*)>>);
+
+template <bool Noexcept>
+struct CallableL {
+  int operator()(char*) & noexcept(Noexcept);
+};
+static_assert(std::is_same_v<decltype(std::packaged_task{CallableL<true>{}}), std::packaged_task<int(char*)>>);
+static_assert(std::is_same_v<decltype(std::packaged_task{CallableL<false>{}}), std::packaged_task<int(char*)>>);
+
+template <bool Noexcept>
+struct CallableCL {
+  int operator()(char*) const & noexcept(Noexcept);
+};
+static_assert(std::is_same_v<decltype(std::packaged_task{CallableCL<true>{}}), std::packaged_task<int(char*)>>);
+static_assert(std::is_same_v<decltype(std::packaged_task{CallableCL<false>{}}), std::packaged_task<int(char*)>>);
+
+template <bool Noexcept>
+struct CallableVL {
+  int operator()(char*) const noexcept(Noexcept);
+};
+static_assert(std::is_same_v<decltype(std::packaged_task{CallableVL<true>{}}), std::packaged_task<int(char*)>>);
+static_assert(std::is_same_v<decltype(std::packaged_task{CallableVL<false>{}}), std::packaged_task<int(char*)>>);
+
+template <bool Noexcept>
+struct CallableCVL {
+  int operator()(char*) const volatile & noexcept(Noexcept);
+};
+static_assert(std::is_same_v<decltype(std::packaged_task{CallableCVL<true>{}}), std::packaged_task<int(char*)>>);
+static_assert(std::is_same_v<decltype(std::packaged_task{CallableCVL<false>{}}), std::packaged_task<int(char*)>>);

diff  --git a/libcxx/test/std/thread/futures/futures.task/futures.task.members/ctad.static.compile.pass.cpp b/libcxx/test/std/thread/futures/futures.task/futures.task.members/ctad.static.compile.pass.cpp
new file mode 100644
index 0000000000000..f982f22d308b8
--- /dev/null
+++ b/libcxx/test/std/thread/futures/futures.task/futures.task.members/ctad.static.compile.pass.cpp
@@ -0,0 +1,26 @@
+//===----------------------------------------------------------------------===//
+//
+// 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: no-threads
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
+// XFAIL: clang-14, clang-15, gcc-12, apple-clang-14
+
+// checks that CTAD for std::packaged_task works properly with static operator() overloads
+
+#include <future>
+#include <type_traits>
+
+struct Except {
+  static int operator()(int*, long*) { return 0; }
+};
+static_assert(std::is_same_v<decltype(std::packaged_task{Except{}}), std::packaged_task<int(int*, long*)>>);
+
+struct Noexcept {
+  static int operator()(int*, long*) noexcept { return 0; }
+};
+static_assert(std::is_same_v<decltype(std::packaged_task{Noexcept{}}), std::packaged_task<int(int*, long*)>>);

diff  --git a/libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.func/func.wrap.func.con/ctad.static.compile.pass.cpp b/libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.func/func.wrap.func.con/ctad.static.compile.pass.cpp
new file mode 100644
index 0000000000000..df7de4c8aa0cf
--- /dev/null
+++ b/libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.func/func.wrap.func.con/ctad.static.compile.pass.cpp
@@ -0,0 +1,41 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+// XFAIL: clang-14, clang-15, gcc-12, apple-clang-14
+
+// checks that CTAD for std::function works properly with static operator() overloads
+
+#include <functional>
+#include <type_traits>
+
+struct Except0 {
+  static void operator()() {}
+};
+static_assert(std::is_same_v<decltype(std::function{Except0{}}), std::function<void()>>);
+
+struct Except1 {
+  static int operator()(int&) { return 0; }
+};
+static_assert(std::is_same_v<decltype(std::function{Except1{}}), std::function<int(int&)>>);
+
+struct Except2 {
+  static int operator()(int*, long*) { return 0; }
+};
+static_assert(std::is_same_v<decltype(std::function{Except2{}}), std::function<int(int*, long*)>>);
+
+struct ExceptD {
+  static int operator()(int*, long* = nullptr) { return 0; }
+};
+static_assert(std::is_same_v<decltype(std::function{ExceptD{}}), std::function<int(int*, long*)>>);
+
+struct Noexcept {
+  static int operator()(int*, long*) noexcept { return 0; }
+};
+
+static_assert(std::is_same_v<decltype(std::function{Noexcept{}}), std::function<int(int*, long*)>>);


        


More information about the libcxx-commits mailing list