From 377c3a9c91785d5df5c0d96121160e6210204cc0 Mon Sep 17 00:00:00 2001 From: Pedro Alves Date: Fri, 5 Aug 2022 16:12:56 +0200 Subject: Introduce gdb::make_function_view This adds gdb::make_function_view, which lets you create a function view from a callable without specifying the function_view's template parameter. For example, this: auto lambda = [&] (int) { ... }; auto fv = gdb::make_function_view (lambda); instead of: auto lambda = [&] (int) { ... }; gdb::function_view fv = lambda; It is particularly useful if you have a template function with an optional function_view parameter, whose type depends on the function's template parameters. Like: template void my_function (T v, gdb::function_view callback = nullptr); For such a function, the type of the callback argument you pass must already be a function_view. I.e., this wouldn't compile: auto lambda = [&] (int) { ... }; my_function (1, lambda); With gdb::make_function_view, you can write the call like so: auto lambda = [&] (int) { ... }; my_function (1, gdb::make_function_view (lambda)); Unit tests included. Tested by building with GCC 9.4, Clang 10, and GCC 4.8.5, on x86_64 GNU/Linux, and running the unit tests. Change-Id: I5c4b3b4455ed6f0d8878cf1be189bea3ee63f626 --- gdbsupport/function-view.h | 127 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 127 insertions(+) (limited to 'gdbsupport') diff --git a/gdbsupport/function-view.h b/gdbsupport/function-view.h index 1875cd104b7..9f8a8680cf4 100644 --- a/gdbsupport/function-view.h +++ b/gdbsupport/function-view.h @@ -148,6 +148,47 @@ iterate_over_foos (process_one_foo); + There's also a gdb::make_function_view function that you can use to + automatically create a function_view from a callable without having + to specify the function_view's template parameter. E.g.: + + auto lambda = [&] (int) { ... }; + auto fv = gdb::make_function_view (lambda); + + This can be useful for example when calling a template function + whose function_view parameter type depends on the function's + template parameters. In such case, you can't rely on implicit + callable->function_view conversion for the function_view argument. + You must pass a function_view argument already of the right type to + the template function. E.g., with this: + + template + void my_function (T v, gdb::function_view callback = nullptr); + + this wouldn't compile: + + auto lambda = [&] (int) { ... }; + my_function (1, lambda); + + Note that this immediately dangles the temporary lambda object: + + gdb::function_view fv = [&] (int) { ... }; // dangles + my_function (fv); + + To avoid the dangling you'd have to use a named temporary for the + lambda: + + auto lambda = [&] (int) { ... }; + gdb::function_view fv = lambda; + my_function (fv); + + Using gdb::make_function_view instead automatically deduces the + function_view's full type, and, avoids worrying about dangling. For + the example above, we could write instead: + + auto lambda = [&] (int) { ... }; + my_function (1, gdb::make_function_view (lambda)); + You can find unit tests covering the whole API in unittests/function-view-selftests.c. */ @@ -318,6 +359,92 @@ constexpr inline bool operator!= (std::nullptr_t, const function_view &f) noexcept { return static_cast (f); } +namespace fv_detail { + +/* Helper traits type to automatically find the right function_view + type for a callable. */ + +/* Use partial specialization to get access to the callable's + signature, for all the different callable variants. */ + +template +struct function_view_traits; + +/* Main partial specialization with plain function signature type. + All others end up redirected here. */ +template +struct function_view_traits +{ + using type = gdb::function_view; +}; + +/* Function pointers. */ +template +struct function_view_traits + : function_view_traits +{ +}; + +/* Function references. */ +template +struct function_view_traits + : function_view_traits +{ +}; + +/* Reference to function pointers. */ +template +struct function_view_traits + : function_view_traits +{ +}; + +/* Reference to const function pointers. */ +template +struct function_view_traits + : function_view_traits +{ +}; + +/* Const member functions. function_view doesn't support these, but + we need this in order to extract the type of function objects. + Lambdas pass here, after starting at the operator() case, + below. */ +template +struct function_view_traits + : function_view_traits +{ +}; + +/* Member functions. Ditto, for function objects with non-const + operator(). */ +template +struct function_view_traits + : function_view_traits +{ +}; + +/* Function objects, lambdas, std::function, any type that defines + operator(). */ +template +struct function_view_traits + : function_view_traits ::type::operator())> +{ +}; + +} /* namespace fv_detail */ + +/* Make a function_view from a callable. Useful to automatically + deduce the function_view's template argument type. */ +template +auto make_function_view (Callable &&callable) + -> typename fv_detail::function_view_traits::type +{ + using fv = typename fv_detail::function_view_traits::type; + return fv (std::forward (callable)); +} + } /* namespace gdb */ #endif -- cgit v1.2.1