xref: /netbsd-src/external/gpl3/gdb/dist/gdbsupport/function-view.h (revision 5ba1f45f2a09259cc846f20c7c5501604d633c90)
1*5ba1f45fSchristos /* Copyright (C) 2017-2024 Free Software Foundation, Inc.
28dffb485Schristos 
38dffb485Schristos    This file is part of GDB.
48dffb485Schristos 
58dffb485Schristos    This program is free software; you can redistribute it and/or modify
68dffb485Schristos    it under the terms of the GNU General Public License as published by
78dffb485Schristos    the Free Software Foundation; either version 3 of the License, or
88dffb485Schristos    (at your option) any later version.
98dffb485Schristos 
108dffb485Schristos    This program is distributed in the hope that it will be useful,
118dffb485Schristos    but WITHOUT ANY WARRANTY; without even the implied warranty of
128dffb485Schristos    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
138dffb485Schristos    GNU General Public License for more details.
148dffb485Schristos 
158dffb485Schristos    You should have received a copy of the GNU General Public License
168dffb485Schristos    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
178dffb485Schristos 
188dffb485Schristos #ifndef COMMON_FUNCTION_VIEW_H
198dffb485Schristos #define COMMON_FUNCTION_VIEW_H
208dffb485Schristos 
218dffb485Schristos /* function_view is a polymorphic type-erasing wrapper class that
228dffb485Schristos    encapsulates a non-owning reference to arbitrary callable objects.
238dffb485Schristos 
248dffb485Schristos    A way to put it is that function_view is to std::function like
258dffb485Schristos    std::string_view is to std::string.  While std::function stores a
268dffb485Schristos    type-erased callable object internally, function_view holds a
278dffb485Schristos    type-erased reference to an external callable object.
288dffb485Schristos 
298dffb485Schristos    This is meant to be used as callback type of a function that:
308dffb485Schristos 
318dffb485Schristos      #1 - Takes a callback as parameter.
328dffb485Schristos 
338dffb485Schristos      #2 - Wants to support arbitrary callable objects as callback type
348dffb485Schristos 	  (e.g., stateful function objects, lambda closures, free
358dffb485Schristos 	  functions).
368dffb485Schristos 
378dffb485Schristos      #3 - Does not store the callback anywhere; instead the function
388dffb485Schristos 	  just calls the callback directly or forwards it to some
398dffb485Schristos 	  other function that calls it.
408dffb485Schristos 
418dffb485Schristos      #4 - Can't be, or we don't want it to be, a template function
428dffb485Schristos 	  with the callable type as template parameter.  For example,
438dffb485Schristos 	  when the callback is a parameter of a virtual member
448dffb485Schristos 	  function, or when putting the function template in a header
458dffb485Schristos 	  would expose too much implementation detail.
468dffb485Schristos 
478dffb485Schristos    Note that the C-style "function pointer" + "void *data" callback
488dffb485Schristos    parameter idiom fails requirement #2 above.  Please don't add new
498dffb485Schristos    uses of that idiom.  I.e., something like this wouldn't work;
508dffb485Schristos 
518dffb485Schristos     typedef bool (iterate_over_foos_cb) (foo *f, void *user_data),
528dffb485Schristos     void iterate_over_foos (iterate_over_foos_cb *callback, void *user_data);
538dffb485Schristos 
548dffb485Schristos     foo *find_foo_by_type (int type)
558dffb485Schristos     {
568dffb485Schristos       foo *found = nullptr;
578dffb485Schristos 
588dffb485Schristos       iterate_over_foos ([&] (foo *f, void *data)
598dffb485Schristos 	{
608dffb485Schristos 	  if (foo->type == type)
618dffb485Schristos 	    {
628dffb485Schristos 	      found = foo;
638dffb485Schristos 	      return true; // stop iterating
648dffb485Schristos 	    }
658dffb485Schristos 	  return false; // continue iterating
668dffb485Schristos 	}, NULL);
678dffb485Schristos 
688dffb485Schristos       return found;
698dffb485Schristos     }
708dffb485Schristos 
718dffb485Schristos    The above wouldn't compile, because lambdas with captures can't be
728dffb485Schristos    implicitly converted to a function pointer (because a capture means
738dffb485Schristos    some context data must be passed to the lambda somehow).
748dffb485Schristos 
758dffb485Schristos    C++11 gave us std::function as type-erased wrapper around arbitrary
768dffb485Schristos    callables, however, std::function is not an ideal fit for transient
778dffb485Schristos    callbacks such as the use case above.  For this use case, which is
788dffb485Schristos    quite pervasive, a function_view is a better choice, because while
798dffb485Schristos    function_view is light and does not require any heap allocation,
808dffb485Schristos    std::function is a heavy-weight object with value semantics that
818dffb485Schristos    generally requires a heap allocation on construction/assignment of
828dffb485Schristos    the target callable.  In addition, while it is possible to use
838dffb485Schristos    std::function in such a way that avoids most of the overhead by
848dffb485Schristos    making sure to only construct it with callables of types that fit
858dffb485Schristos    std::function's small object optimization, such as function
868dffb485Schristos    pointers and std::reference_wrapper callables, that is quite
878dffb485Schristos    inconvenient in practice, because restricting to free-function
888dffb485Schristos    callables would imply no state/capture/closure, which we need in
898dffb485Schristos    most cases, and std::reference_wrapper implies remembering to use
908dffb485Schristos    std::ref/std::cref where the callable is constructed, with the
918dffb485Schristos    added inconvenience that std::ref/std::cref have deleted rvalue-ref
928dffb485Schristos    overloads, meaning you can't use unnamed/temporary lambdas with
938dffb485Schristos    them.
948dffb485Schristos 
958dffb485Schristos    Note that because function_view is a non-owning view of a callable,
968dffb485Schristos    care must be taken to ensure that the callable outlives the
978dffb485Schristos    function_view that calls it.  This is not really a problem for the
988dffb485Schristos    use case function_view is intended for, such as passing a temporary
998dffb485Schristos    function object / lambda to a function that accepts a callback,
1008dffb485Schristos    because in those cases, the temporary is guaranteed to be live
1018dffb485Schristos    until the called function returns.
1028dffb485Schristos 
1038dffb485Schristos    Calling a function_view with no associated target is undefined,
1048dffb485Schristos    unlike with std::function, which throws std::bad_function_call.
1058dffb485Schristos    This is by design, to avoid the otherwise necessary NULL check in
1068dffb485Schristos    function_view::operator().
1078dffb485Schristos 
1088dffb485Schristos    Since function_view objects are small (a pair of pointers), they
1098dffb485Schristos    should generally be passed around by value.
1108dffb485Schristos 
1118dffb485Schristos    Usage:
1128dffb485Schristos 
1138dffb485Schristos    Given this function that accepts a callback:
1148dffb485Schristos 
1158dffb485Schristos     void
1168dffb485Schristos     iterate_over_foos (gdb::function_view<void (foo *)> callback)
1178dffb485Schristos     {
1188dffb485Schristos        for (auto &foo : foos)
1198dffb485Schristos 	 callback (&foo);
1208dffb485Schristos     }
1218dffb485Schristos 
1228dffb485Schristos    you can call it like this, passing a lambda as callback:
1238dffb485Schristos 
1248dffb485Schristos     iterate_over_foos ([&] (foo *f)
1258dffb485Schristos       {
1268dffb485Schristos 	process_one_foo (f);
1278dffb485Schristos       });
1288dffb485Schristos 
1298dffb485Schristos    or like this, passing a function object as callback:
1308dffb485Schristos 
1318dffb485Schristos     struct function_object
1328dffb485Schristos     {
1338dffb485Schristos       void operator() (foo *f)
1348dffb485Schristos       {
1358dffb485Schristos 	if (s->check ())
1368dffb485Schristos 	  process_one_foo (f);
1378dffb485Schristos       }
1388dffb485Schristos 
1398dffb485Schristos       // some state
1408dffb485Schristos       state *s;
1418dffb485Schristos     };
1428dffb485Schristos 
1438dffb485Schristos     state mystate;
1448dffb485Schristos     function_object matcher {&mystate};
1458dffb485Schristos     iterate_over_foos (matcher);
1468dffb485Schristos 
1478dffb485Schristos   or like this, passing a function pointer as callback:
1488dffb485Schristos 
1498dffb485Schristos     iterate_over_foos (process_one_foo);
1508dffb485Schristos 
1514b169a6bSchristos   There's also a gdb::make_function_view function that you can use to
1524b169a6bSchristos   automatically create a function_view from a callable without having
1534b169a6bSchristos   to specify the function_view's template parameter.  E.g.:
1544b169a6bSchristos 
1554b169a6bSchristos     auto lambda = [&] (int) { ... };
1564b169a6bSchristos     auto fv = gdb::make_function_view (lambda);
1574b169a6bSchristos 
1584b169a6bSchristos   This can be useful for example when calling a template function
1594b169a6bSchristos   whose function_view parameter type depends on the function's
1604b169a6bSchristos   template parameters.  In such case, you can't rely on implicit
1614b169a6bSchristos   callable->function_view conversion for the function_view argument.
1624b169a6bSchristos   You must pass a function_view argument already of the right type to
1634b169a6bSchristos   the template function.  E.g., with this:
1644b169a6bSchristos 
1654b169a6bSchristos     template<typename T>
1664b169a6bSchristos     void my_function (T v, gdb::function_view<void(T)> callback = nullptr);
1674b169a6bSchristos 
1684b169a6bSchristos   this wouldn't compile:
1694b169a6bSchristos 
1704b169a6bSchristos     auto lambda = [&] (int) { ... };
1714b169a6bSchristos     my_function (1, lambda);
1724b169a6bSchristos 
1734b169a6bSchristos   Note that this immediately dangles the temporary lambda object:
1744b169a6bSchristos 
1754b169a6bSchristos     gdb::function_view<void(int)> fv = [&] (int) { ... };  // dangles
1764b169a6bSchristos     my_function (fv);
1774b169a6bSchristos 
1784b169a6bSchristos   To avoid the dangling you'd have to use a named temporary for the
1794b169a6bSchristos   lambda:
1804b169a6bSchristos 
1814b169a6bSchristos     auto lambda = [&] (int) { ... };
1824b169a6bSchristos     gdb::function_view<void(int)> fv = lambda;
1834b169a6bSchristos     my_function (fv);
1844b169a6bSchristos 
1854b169a6bSchristos   Using gdb::make_function_view instead automatically deduces the
1864b169a6bSchristos   function_view's full type, and, avoids worrying about dangling.  For
1874b169a6bSchristos   the example above, we could write instead:
1884b169a6bSchristos 
1894b169a6bSchristos     auto lambda = [&] (int) { ... };
1904b169a6bSchristos     my_function (1, gdb::make_function_view (lambda));
1914b169a6bSchristos 
1928dffb485Schristos   You can find unit tests covering the whole API in
1938dffb485Schristos   unittests/function-view-selftests.c.  */
1948dffb485Schristos 
195*5ba1f45fSchristos #include <type_traits>
1968dffb485Schristos namespace gdb {
1978dffb485Schristos 
1988dffb485Schristos namespace fv_detail {
1998dffb485Schristos /* Bits shared by all function_view instantiations that do not depend
2008dffb485Schristos    on the template parameters.  */
2018dffb485Schristos 
2028dffb485Schristos /* Storage for the erased callable.  This is a union in order to be
2038dffb485Schristos    able to save both a function object (data) pointer or a function
2048dffb485Schristos    pointer without triggering undefined behavior.  */
2058dffb485Schristos union erased_callable
2068dffb485Schristos {
2078dffb485Schristos   /* For function objects.  */
2088dffb485Schristos   void *data;
2098dffb485Schristos 
2108dffb485Schristos     /* For function pointers.  */
2118dffb485Schristos   void (*fn) ();
2128dffb485Schristos };
2138dffb485Schristos 
2148dffb485Schristos } /* namespace fv_detail */
2158dffb485Schristos 
2168dffb485Schristos /* Use partial specialization to get access to the callable's
2178dffb485Schristos    signature. */
2188dffb485Schristos template<class Signature>
2198dffb485Schristos struct function_view;
2208dffb485Schristos 
2218dffb485Schristos template<typename Res, typename... Args>
2228dffb485Schristos class function_view<Res (Args...)>
2238dffb485Schristos {
2248dffb485Schristos   template<typename From, typename To>
2258dffb485Schristos   using CompatibleReturnType
2268dffb485Schristos     = Or<std::is_void<To>,
2278dffb485Schristos 	 std::is_same<From, To>,
2288dffb485Schristos 	 std::is_convertible<From, To>>;
2298dffb485Schristos 
2308dffb485Schristos   /* True if Func can be called with Args, and either the result is
2318dffb485Schristos      Res, convertible to Res or Res is void.  */
2328dffb485Schristos   template<typename Callable,
233*5ba1f45fSchristos 	   typename Res2 = typename std::invoke_result<Callable &, Args...>::type>
2348dffb485Schristos   struct IsCompatibleCallable : CompatibleReturnType<Res2, Res>
2358dffb485Schristos   {};
2368dffb485Schristos 
2378dffb485Schristos   /* True if Callable is a function_view.  Used to avoid hijacking the
2388dffb485Schristos      copy ctor.  */
2398dffb485Schristos   template <typename Callable>
2408dffb485Schristos   struct IsFunctionView
2418dffb485Schristos     : std::is_same<function_view, typename std::decay<Callable>::type>
2428dffb485Schristos   {};
2438dffb485Schristos 
2448dffb485Schristos  public:
2458dffb485Schristos 
2468dffb485Schristos   /* NULL by default.  */
2478dffb485Schristos   constexpr function_view () noexcept
2488dffb485Schristos     : m_erased_callable {},
2498dffb485Schristos       m_invoker {}
2508dffb485Schristos   {}
2518dffb485Schristos 
2528dffb485Schristos   /* Default copy/assignment is fine.  */
2538dffb485Schristos   function_view (const function_view &) = default;
2548dffb485Schristos   function_view &operator= (const function_view &) = default;
2558dffb485Schristos 
2568dffb485Schristos   /* This is the main entry point.  Use SFINAE to avoid hijacking the
2578dffb485Schristos      copy constructor and to ensure that the target type is
2588dffb485Schristos      compatible.  */
2598dffb485Schristos   template
2608dffb485Schristos     <typename Callable,
2618dffb485Schristos      typename = Requires<Not<IsFunctionView<Callable>>>,
2628dffb485Schristos      typename = Requires<IsCompatibleCallable<Callable>>>
2638dffb485Schristos   function_view (Callable &&callable) noexcept
2648dffb485Schristos   {
2658dffb485Schristos     bind (callable);
2668dffb485Schristos   }
2678dffb485Schristos 
2688dffb485Schristos   /* Construct a NULL function_view.  */
2698dffb485Schristos   constexpr function_view (std::nullptr_t) noexcept
2708dffb485Schristos     : m_erased_callable {},
2718dffb485Schristos       m_invoker {}
2728dffb485Schristos   {}
2738dffb485Schristos 
2748dffb485Schristos   /* Clear a function_view.  */
2758dffb485Schristos   function_view &operator= (std::nullptr_t) noexcept
2768dffb485Schristos   {
2778dffb485Schristos     m_invoker = nullptr;
2788dffb485Schristos     return *this;
2798dffb485Schristos   }
2808dffb485Schristos 
2818dffb485Schristos   /* Return true if the wrapper has a target, false otherwise.  Note
2828dffb485Schristos      we check M_INVOKER instead of M_ERASED_CALLABLE because we don't
2838dffb485Schristos      know which member of the union is active right now.  */
2848dffb485Schristos   constexpr explicit operator bool () const noexcept
2858dffb485Schristos   { return m_invoker != nullptr; }
2868dffb485Schristos 
2878dffb485Schristos   /* Call the callable.  */
2888dffb485Schristos   Res operator () (Args... args) const
2898dffb485Schristos   { return m_invoker (m_erased_callable, std::forward<Args> (args)...); }
2908dffb485Schristos 
2918dffb485Schristos  private:
2928dffb485Schristos 
2938dffb485Schristos   /* Bind this function_view to a compatible function object
2948dffb485Schristos      reference.  */
2958dffb485Schristos   template <typename Callable>
2968dffb485Schristos   void bind (Callable &callable) noexcept
2978dffb485Schristos   {
2988dffb485Schristos     m_erased_callable.data = (void *) std::addressof (callable);
2998dffb485Schristos     m_invoker = [] (fv_detail::erased_callable ecall, Args... args)
3008dffb485Schristos       noexcept (noexcept (callable (std::forward<Args> (args)...))) -> Res
3018dffb485Schristos       {
3028dffb485Schristos 	auto &restored_callable = *static_cast<Callable *> (ecall.data);
3038dffb485Schristos 	/* The explicit cast to Res avoids a compile error when Res is
3048dffb485Schristos 	   void and the callable returns non-void.  */
3058dffb485Schristos 	return (Res) restored_callable (std::forward<Args> (args)...);
3068dffb485Schristos       };
3078dffb485Schristos   }
3088dffb485Schristos 
3098dffb485Schristos   /* Bind this function_view to a compatible function pointer.
3108dffb485Schristos 
3118dffb485Schristos      Making this a separate function allows avoiding one indirection,
3128dffb485Schristos      by storing the function pointer directly in the storage, instead
3138dffb485Schristos      of a pointer to pointer.  erased_callable is then a union in
3148dffb485Schristos      order to avoid storing a function pointer as a data pointer here,
3158dffb485Schristos      which would be undefined.  */
3168dffb485Schristos   template<class Res2, typename... Args2>
3178dffb485Schristos   void bind (Res2 (*fn) (Args2...)) noexcept
3188dffb485Schristos   {
3198dffb485Schristos     m_erased_callable.fn = reinterpret_cast<void (*) ()> (fn);
3208dffb485Schristos     m_invoker = [] (fv_detail::erased_callable ecall, Args... args)
3218dffb485Schristos       noexcept (noexcept (fn (std::forward<Args> (args)...))) -> Res
3228dffb485Schristos       {
3238dffb485Schristos 	auto restored_fn = reinterpret_cast<Res2 (*) (Args2...)> (ecall.fn);
3248dffb485Schristos 	/* The explicit cast to Res avoids a compile error when Res is
3258dffb485Schristos 	   void and the callable returns non-void.  */
3268dffb485Schristos 	return (Res) restored_fn (std::forward<Args> (args)...);
3278dffb485Schristos       };
3288dffb485Schristos   }
3298dffb485Schristos 
3308dffb485Schristos   /* Storage for the erased callable.  */
3318dffb485Schristos   fv_detail::erased_callable m_erased_callable;
3328dffb485Schristos 
3338dffb485Schristos   /* The invoker.  This is set to a capture-less lambda by one of the
3348dffb485Schristos      'bind' overloads.  The lambda restores the right type of the
3358dffb485Schristos      callable (which is passed as first argument), and forwards the
3368dffb485Schristos      args.  */
3378dffb485Schristos   Res (*m_invoker) (fv_detail::erased_callable, Args...);
3388dffb485Schristos };
3398dffb485Schristos 
3408dffb485Schristos /* Allow comparison with NULL.  Defer the work to the in-class
3418dffb485Schristos    operator bool implementation.  */
3428dffb485Schristos 
3438dffb485Schristos template<typename Res, typename... Args>
3448dffb485Schristos constexpr inline bool
3458dffb485Schristos operator== (const function_view<Res (Args...)> &f, std::nullptr_t) noexcept
3468dffb485Schristos { return !static_cast<bool> (f); }
3478dffb485Schristos 
3488dffb485Schristos template<typename Res, typename... Args>
3498dffb485Schristos constexpr inline bool
3508dffb485Schristos operator== (std::nullptr_t, const function_view<Res (Args...)> &f) noexcept
3518dffb485Schristos { return !static_cast<bool> (f); }
3528dffb485Schristos 
3538dffb485Schristos template<typename Res, typename... Args>
3548dffb485Schristos constexpr inline bool
3558dffb485Schristos operator!= (const function_view<Res (Args...)> &f, std::nullptr_t) noexcept
3568dffb485Schristos { return static_cast<bool> (f); }
3578dffb485Schristos 
3588dffb485Schristos template<typename Res, typename... Args>
3598dffb485Schristos constexpr inline bool
3608dffb485Schristos operator!= (std::nullptr_t, const function_view<Res (Args...)> &f) noexcept
3618dffb485Schristos { return static_cast<bool> (f); }
3628dffb485Schristos 
3634b169a6bSchristos namespace fv_detail {
3644b169a6bSchristos 
3654b169a6bSchristos /* Helper traits type to automatically find the right function_view
3664b169a6bSchristos    type for a callable.  */
3674b169a6bSchristos 
3684b169a6bSchristos /* Use partial specialization to get access to the callable's
3694b169a6bSchristos    signature, for all the different callable variants.  */
3704b169a6bSchristos 
3714b169a6bSchristos template<typename>
3724b169a6bSchristos struct function_view_traits;
3734b169a6bSchristos 
3744b169a6bSchristos /* Main partial specialization with plain function signature type.
3754b169a6bSchristos    All others end up redirected here.  */
3764b169a6bSchristos template<typename Res, typename... Args>
3774b169a6bSchristos struct function_view_traits<Res (Args...)>
3784b169a6bSchristos {
3794b169a6bSchristos   using type = gdb::function_view<Res (Args...)>;
3804b169a6bSchristos };
3814b169a6bSchristos 
3824b169a6bSchristos /* Function pointers.  */
3834b169a6bSchristos template<typename Res, typename... Args>
3844b169a6bSchristos struct function_view_traits<Res (*) (Args...)>
3854b169a6bSchristos   : function_view_traits<Res (Args...)>
3864b169a6bSchristos {
3874b169a6bSchristos };
3884b169a6bSchristos 
3894b169a6bSchristos /* Function references.  */
3904b169a6bSchristos template<typename Res, typename... Args>
3914b169a6bSchristos struct function_view_traits<Res (&) (Args...)>
3924b169a6bSchristos   : function_view_traits<Res (Args...)>
3934b169a6bSchristos {
3944b169a6bSchristos };
3954b169a6bSchristos 
3964b169a6bSchristos /* Reference to function pointers.  */
3974b169a6bSchristos template<typename Res, typename... Args>
3984b169a6bSchristos struct function_view_traits<Res (*&) (Args...)>
3994b169a6bSchristos   : function_view_traits<Res (Args...)>
4004b169a6bSchristos {
4014b169a6bSchristos };
4024b169a6bSchristos 
4034b169a6bSchristos /* Reference to const function pointers.  */
4044b169a6bSchristos template<typename Res, typename... Args>
4054b169a6bSchristos struct function_view_traits<Res (* const &) (Args...)>
4064b169a6bSchristos   : function_view_traits<Res (Args...)>
4074b169a6bSchristos {
4084b169a6bSchristos };
4094b169a6bSchristos 
4104b169a6bSchristos /* Const member functions.  function_view doesn't support these, but
4114b169a6bSchristos    we need this in order to extract the type of function objects.
4124b169a6bSchristos    Lambdas pass here, after starting at the operator() case,
4134b169a6bSchristos    below.  */
4144b169a6bSchristos template<typename Res, typename Class, typename... Args>
4154b169a6bSchristos struct function_view_traits<Res (Class::*) (Args...) const>
4164b169a6bSchristos   : function_view_traits<Res (Args...)>
4174b169a6bSchristos {
4184b169a6bSchristos };
4194b169a6bSchristos 
4204b169a6bSchristos /* Member functions.  Ditto, for function objects with non-const
4214b169a6bSchristos    operator().  */
4224b169a6bSchristos template<typename Res, typename Class, typename... Args>
4234b169a6bSchristos struct function_view_traits<Res (Class::*) (Args...)>
4244b169a6bSchristos   : function_view_traits<Res (Args...)>
4254b169a6bSchristos {
4264b169a6bSchristos };
4274b169a6bSchristos 
4284b169a6bSchristos /* Function objects, lambdas, std::function, any type that defines
4294b169a6bSchristos    operator().  */
4304b169a6bSchristos template<typename FuncObj>
4314b169a6bSchristos struct function_view_traits
4324b169a6bSchristos   : function_view_traits <decltype
4334b169a6bSchristos 			  (&std::remove_reference<FuncObj>::type::operator())>
4344b169a6bSchristos {
4354b169a6bSchristos };
4364b169a6bSchristos 
4374b169a6bSchristos } /* namespace fv_detail */
4384b169a6bSchristos 
4394b169a6bSchristos /* Make a function_view from a callable.  Useful to automatically
4404b169a6bSchristos    deduce the function_view's template argument type.  */
4414b169a6bSchristos template<typename Callable>
4424b169a6bSchristos auto make_function_view (Callable &&callable)
4434b169a6bSchristos   -> typename fv_detail::function_view_traits<Callable>::type
4444b169a6bSchristos {
4454b169a6bSchristos   using fv = typename fv_detail::function_view_traits<Callable>::type;
4464b169a6bSchristos   return fv (std::forward<Callable> (callable));
4474b169a6bSchristos }
4484b169a6bSchristos 
4498dffb485Schristos } /* namespace gdb */
4508dffb485Schristos 
4518dffb485Schristos #endif
452