Home | History | Annotate | Line # | Download | only in gdbsupport
function-view.h revision 1.1.1.2
      1  1.1.1.2  christos /* Copyright (C) 2017-2023 Free Software Foundation, Inc.
      2      1.1  christos 
      3      1.1  christos    This file is part of GDB.
      4      1.1  christos 
      5      1.1  christos    This program is free software; you can redistribute it and/or modify
      6      1.1  christos    it under the terms of the GNU General Public License as published by
      7      1.1  christos    the Free Software Foundation; either version 3 of the License, or
      8      1.1  christos    (at your option) any later version.
      9      1.1  christos 
     10      1.1  christos    This program is distributed in the hope that it will be useful,
     11      1.1  christos    but WITHOUT ANY WARRANTY; without even the implied warranty of
     12      1.1  christos    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     13      1.1  christos    GNU General Public License for more details.
     14      1.1  christos 
     15      1.1  christos    You should have received a copy of the GNU General Public License
     16      1.1  christos    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
     17      1.1  christos 
     18      1.1  christos #ifndef COMMON_FUNCTION_VIEW_H
     19      1.1  christos #define COMMON_FUNCTION_VIEW_H
     20      1.1  christos 
     21      1.1  christos /* function_view is a polymorphic type-erasing wrapper class that
     22      1.1  christos    encapsulates a non-owning reference to arbitrary callable objects.
     23      1.1  christos 
     24      1.1  christos    A way to put it is that function_view is to std::function like
     25      1.1  christos    std::string_view is to std::string.  While std::function stores a
     26      1.1  christos    type-erased callable object internally, function_view holds a
     27      1.1  christos    type-erased reference to an external callable object.
     28      1.1  christos 
     29      1.1  christos    This is meant to be used as callback type of a function that:
     30      1.1  christos 
     31      1.1  christos      #1 - Takes a callback as parameter.
     32      1.1  christos 
     33      1.1  christos      #2 - Wants to support arbitrary callable objects as callback type
     34      1.1  christos 	  (e.g., stateful function objects, lambda closures, free
     35      1.1  christos 	  functions).
     36      1.1  christos 
     37      1.1  christos      #3 - Does not store the callback anywhere; instead the function
     38      1.1  christos 	  just calls the callback directly or forwards it to some
     39      1.1  christos 	  other function that calls it.
     40      1.1  christos 
     41      1.1  christos      #4 - Can't be, or we don't want it to be, a template function
     42      1.1  christos 	  with the callable type as template parameter.  For example,
     43      1.1  christos 	  when the callback is a parameter of a virtual member
     44      1.1  christos 	  function, or when putting the function template in a header
     45      1.1  christos 	  would expose too much implementation detail.
     46      1.1  christos 
     47      1.1  christos    Note that the C-style "function pointer" + "void *data" callback
     48      1.1  christos    parameter idiom fails requirement #2 above.  Please don't add new
     49      1.1  christos    uses of that idiom.  I.e., something like this wouldn't work;
     50      1.1  christos 
     51      1.1  christos     typedef bool (iterate_over_foos_cb) (foo *f, void *user_data),
     52      1.1  christos     void iterate_over_foos (iterate_over_foos_cb *callback, void *user_data);
     53      1.1  christos 
     54      1.1  christos     foo *find_foo_by_type (int type)
     55      1.1  christos     {
     56      1.1  christos       foo *found = nullptr;
     57      1.1  christos 
     58      1.1  christos       iterate_over_foos ([&] (foo *f, void *data)
     59      1.1  christos 	{
     60      1.1  christos 	  if (foo->type == type)
     61      1.1  christos 	    {
     62      1.1  christos 	      found = foo;
     63      1.1  christos 	      return true; // stop iterating
     64      1.1  christos 	    }
     65      1.1  christos 	  return false; // continue iterating
     66      1.1  christos 	}, NULL);
     67      1.1  christos 
     68      1.1  christos       return found;
     69      1.1  christos     }
     70      1.1  christos 
     71      1.1  christos    The above wouldn't compile, because lambdas with captures can't be
     72      1.1  christos    implicitly converted to a function pointer (because a capture means
     73      1.1  christos    some context data must be passed to the lambda somehow).
     74      1.1  christos 
     75      1.1  christos    C++11 gave us std::function as type-erased wrapper around arbitrary
     76      1.1  christos    callables, however, std::function is not an ideal fit for transient
     77      1.1  christos    callbacks such as the use case above.  For this use case, which is
     78      1.1  christos    quite pervasive, a function_view is a better choice, because while
     79      1.1  christos    function_view is light and does not require any heap allocation,
     80      1.1  christos    std::function is a heavy-weight object with value semantics that
     81      1.1  christos    generally requires a heap allocation on construction/assignment of
     82      1.1  christos    the target callable.  In addition, while it is possible to use
     83      1.1  christos    std::function in such a way that avoids most of the overhead by
     84      1.1  christos    making sure to only construct it with callables of types that fit
     85      1.1  christos    std::function's small object optimization, such as function
     86      1.1  christos    pointers and std::reference_wrapper callables, that is quite
     87      1.1  christos    inconvenient in practice, because restricting to free-function
     88      1.1  christos    callables would imply no state/capture/closure, which we need in
     89      1.1  christos    most cases, and std::reference_wrapper implies remembering to use
     90      1.1  christos    std::ref/std::cref where the callable is constructed, with the
     91      1.1  christos    added inconvenience that std::ref/std::cref have deleted rvalue-ref
     92      1.1  christos    overloads, meaning you can't use unnamed/temporary lambdas with
     93      1.1  christos    them.
     94      1.1  christos 
     95      1.1  christos    Note that because function_view is a non-owning view of a callable,
     96      1.1  christos    care must be taken to ensure that the callable outlives the
     97      1.1  christos    function_view that calls it.  This is not really a problem for the
     98      1.1  christos    use case function_view is intended for, such as passing a temporary
     99      1.1  christos    function object / lambda to a function that accepts a callback,
    100      1.1  christos    because in those cases, the temporary is guaranteed to be live
    101      1.1  christos    until the called function returns.
    102      1.1  christos 
    103      1.1  christos    Calling a function_view with no associated target is undefined,
    104      1.1  christos    unlike with std::function, which throws std::bad_function_call.
    105      1.1  christos    This is by design, to avoid the otherwise necessary NULL check in
    106      1.1  christos    function_view::operator().
    107      1.1  christos 
    108      1.1  christos    Since function_view objects are small (a pair of pointers), they
    109      1.1  christos    should generally be passed around by value.
    110      1.1  christos 
    111      1.1  christos    Usage:
    112      1.1  christos 
    113      1.1  christos    Given this function that accepts a callback:
    114      1.1  christos 
    115      1.1  christos     void
    116      1.1  christos     iterate_over_foos (gdb::function_view<void (foo *)> callback)
    117      1.1  christos     {
    118      1.1  christos        for (auto &foo : foos)
    119      1.1  christos 	 callback (&foo);
    120      1.1  christos     }
    121      1.1  christos 
    122      1.1  christos    you can call it like this, passing a lambda as callback:
    123      1.1  christos 
    124      1.1  christos     iterate_over_foos ([&] (foo *f)
    125      1.1  christos       {
    126      1.1  christos 	process_one_foo (f);
    127      1.1  christos       });
    128      1.1  christos 
    129      1.1  christos    or like this, passing a function object as callback:
    130      1.1  christos 
    131      1.1  christos     struct function_object
    132      1.1  christos     {
    133      1.1  christos       void operator() (foo *f)
    134      1.1  christos       {
    135      1.1  christos 	if (s->check ())
    136      1.1  christos 	  process_one_foo (f);
    137      1.1  christos       }
    138      1.1  christos 
    139      1.1  christos       // some state
    140      1.1  christos       state *s;
    141      1.1  christos     };
    142      1.1  christos 
    143      1.1  christos     state mystate;
    144      1.1  christos     function_object matcher {&mystate};
    145      1.1  christos     iterate_over_foos (matcher);
    146      1.1  christos 
    147      1.1  christos   or like this, passing a function pointer as callback:
    148      1.1  christos 
    149      1.1  christos     iterate_over_foos (process_one_foo);
    150      1.1  christos 
    151  1.1.1.2  christos   There's also a gdb::make_function_view function that you can use to
    152  1.1.1.2  christos   automatically create a function_view from a callable without having
    153  1.1.1.2  christos   to specify the function_view's template parameter.  E.g.:
    154  1.1.1.2  christos 
    155  1.1.1.2  christos     auto lambda = [&] (int) { ... };
    156  1.1.1.2  christos     auto fv = gdb::make_function_view (lambda);
    157  1.1.1.2  christos 
    158  1.1.1.2  christos   This can be useful for example when calling a template function
    159  1.1.1.2  christos   whose function_view parameter type depends on the function's
    160  1.1.1.2  christos   template parameters.  In such case, you can't rely on implicit
    161  1.1.1.2  christos   callable->function_view conversion for the function_view argument.
    162  1.1.1.2  christos   You must pass a function_view argument already of the right type to
    163  1.1.1.2  christos   the template function.  E.g., with this:
    164  1.1.1.2  christos 
    165  1.1.1.2  christos     template<typename T>
    166  1.1.1.2  christos     void my_function (T v, gdb::function_view<void(T)> callback = nullptr);
    167  1.1.1.2  christos 
    168  1.1.1.2  christos   this wouldn't compile:
    169  1.1.1.2  christos 
    170  1.1.1.2  christos     auto lambda = [&] (int) { ... };
    171  1.1.1.2  christos     my_function (1, lambda);
    172  1.1.1.2  christos 
    173  1.1.1.2  christos   Note that this immediately dangles the temporary lambda object:
    174  1.1.1.2  christos 
    175  1.1.1.2  christos     gdb::function_view<void(int)> fv = [&] (int) { ... };  // dangles
    176  1.1.1.2  christos     my_function (fv);
    177  1.1.1.2  christos 
    178  1.1.1.2  christos   To avoid the dangling you'd have to use a named temporary for the
    179  1.1.1.2  christos   lambda:
    180  1.1.1.2  christos 
    181  1.1.1.2  christos     auto lambda = [&] (int) { ... };
    182  1.1.1.2  christos     gdb::function_view<void(int)> fv = lambda;
    183  1.1.1.2  christos     my_function (fv);
    184  1.1.1.2  christos 
    185  1.1.1.2  christos   Using gdb::make_function_view instead automatically deduces the
    186  1.1.1.2  christos   function_view's full type, and, avoids worrying about dangling.  For
    187  1.1.1.2  christos   the example above, we could write instead:
    188  1.1.1.2  christos 
    189  1.1.1.2  christos     auto lambda = [&] (int) { ... };
    190  1.1.1.2  christos     my_function (1, gdb::make_function_view (lambda));
    191  1.1.1.2  christos 
    192      1.1  christos   You can find unit tests covering the whole API in
    193      1.1  christos   unittests/function-view-selftests.c.  */
    194      1.1  christos 
    195  1.1.1.2  christos #include "invoke-result.h"
    196      1.1  christos namespace gdb {
    197      1.1  christos 
    198      1.1  christos namespace fv_detail {
    199      1.1  christos /* Bits shared by all function_view instantiations that do not depend
    200      1.1  christos    on the template parameters.  */
    201      1.1  christos 
    202      1.1  christos /* Storage for the erased callable.  This is a union in order to be
    203      1.1  christos    able to save both a function object (data) pointer or a function
    204      1.1  christos    pointer without triggering undefined behavior.  */
    205      1.1  christos union erased_callable
    206      1.1  christos {
    207      1.1  christos   /* For function objects.  */
    208      1.1  christos   void *data;
    209      1.1  christos 
    210      1.1  christos     /* For function pointers.  */
    211      1.1  christos   void (*fn) ();
    212      1.1  christos };
    213      1.1  christos 
    214      1.1  christos } /* namespace fv_detail */
    215      1.1  christos 
    216      1.1  christos /* Use partial specialization to get access to the callable's
    217      1.1  christos    signature. */
    218      1.1  christos template<class Signature>
    219      1.1  christos struct function_view;
    220      1.1  christos 
    221      1.1  christos template<typename Res, typename... Args>
    222      1.1  christos class function_view<Res (Args...)>
    223      1.1  christos {
    224      1.1  christos   template<typename From, typename To>
    225      1.1  christos   using CompatibleReturnType
    226      1.1  christos     = Or<std::is_void<To>,
    227      1.1  christos 	 std::is_same<From, To>,
    228      1.1  christos 	 std::is_convertible<From, To>>;
    229      1.1  christos 
    230      1.1  christos   /* True if Func can be called with Args, and either the result is
    231      1.1  christos      Res, convertible to Res or Res is void.  */
    232      1.1  christos   template<typename Callable,
    233  1.1.1.2  christos 	   typename Res2 = typename gdb::invoke_result<Callable &, Args...>::type>
    234      1.1  christos   struct IsCompatibleCallable : CompatibleReturnType<Res2, Res>
    235      1.1  christos   {};
    236      1.1  christos 
    237      1.1  christos   /* True if Callable is a function_view.  Used to avoid hijacking the
    238      1.1  christos      copy ctor.  */
    239      1.1  christos   template <typename Callable>
    240      1.1  christos   struct IsFunctionView
    241      1.1  christos     : std::is_same<function_view, typename std::decay<Callable>::type>
    242      1.1  christos   {};
    243      1.1  christos 
    244      1.1  christos  public:
    245      1.1  christos 
    246      1.1  christos   /* NULL by default.  */
    247      1.1  christos   constexpr function_view () noexcept
    248      1.1  christos     : m_erased_callable {},
    249      1.1  christos       m_invoker {}
    250      1.1  christos   {}
    251      1.1  christos 
    252      1.1  christos   /* Default copy/assignment is fine.  */
    253      1.1  christos   function_view (const function_view &) = default;
    254      1.1  christos   function_view &operator= (const function_view &) = default;
    255      1.1  christos 
    256      1.1  christos   /* This is the main entry point.  Use SFINAE to avoid hijacking the
    257      1.1  christos      copy constructor and to ensure that the target type is
    258      1.1  christos      compatible.  */
    259      1.1  christos   template
    260      1.1  christos     <typename Callable,
    261      1.1  christos      typename = Requires<Not<IsFunctionView<Callable>>>,
    262      1.1  christos      typename = Requires<IsCompatibleCallable<Callable>>>
    263      1.1  christos   function_view (Callable &&callable) noexcept
    264      1.1  christos   {
    265      1.1  christos     bind (callable);
    266      1.1  christos   }
    267      1.1  christos 
    268      1.1  christos   /* Construct a NULL function_view.  */
    269      1.1  christos   constexpr function_view (std::nullptr_t) noexcept
    270      1.1  christos     : m_erased_callable {},
    271      1.1  christos       m_invoker {}
    272      1.1  christos   {}
    273      1.1  christos 
    274      1.1  christos   /* Clear a function_view.  */
    275      1.1  christos   function_view &operator= (std::nullptr_t) noexcept
    276      1.1  christos   {
    277      1.1  christos     m_invoker = nullptr;
    278      1.1  christos     return *this;
    279      1.1  christos   }
    280      1.1  christos 
    281      1.1  christos   /* Return true if the wrapper has a target, false otherwise.  Note
    282      1.1  christos      we check M_INVOKER instead of M_ERASED_CALLABLE because we don't
    283      1.1  christos      know which member of the union is active right now.  */
    284      1.1  christos   constexpr explicit operator bool () const noexcept
    285      1.1  christos   { return m_invoker != nullptr; }
    286      1.1  christos 
    287      1.1  christos   /* Call the callable.  */
    288      1.1  christos   Res operator () (Args... args) const
    289      1.1  christos   { return m_invoker (m_erased_callable, std::forward<Args> (args)...); }
    290      1.1  christos 
    291      1.1  christos  private:
    292      1.1  christos 
    293      1.1  christos   /* Bind this function_view to a compatible function object
    294      1.1  christos      reference.  */
    295      1.1  christos   template <typename Callable>
    296      1.1  christos   void bind (Callable &callable) noexcept
    297      1.1  christos   {
    298      1.1  christos     m_erased_callable.data = (void *) std::addressof (callable);
    299      1.1  christos     m_invoker = [] (fv_detail::erased_callable ecall, Args... args)
    300      1.1  christos       noexcept (noexcept (callable (std::forward<Args> (args)...))) -> Res
    301      1.1  christos       {
    302      1.1  christos 	auto &restored_callable = *static_cast<Callable *> (ecall.data);
    303      1.1  christos 	/* The explicit cast to Res avoids a compile error when Res is
    304      1.1  christos 	   void and the callable returns non-void.  */
    305      1.1  christos 	return (Res) restored_callable (std::forward<Args> (args)...);
    306      1.1  christos       };
    307      1.1  christos   }
    308      1.1  christos 
    309      1.1  christos   /* Bind this function_view to a compatible function pointer.
    310      1.1  christos 
    311      1.1  christos      Making this a separate function allows avoiding one indirection,
    312      1.1  christos      by storing the function pointer directly in the storage, instead
    313      1.1  christos      of a pointer to pointer.  erased_callable is then a union in
    314      1.1  christos      order to avoid storing a function pointer as a data pointer here,
    315      1.1  christos      which would be undefined.  */
    316      1.1  christos   template<class Res2, typename... Args2>
    317      1.1  christos   void bind (Res2 (*fn) (Args2...)) noexcept
    318      1.1  christos   {
    319      1.1  christos     m_erased_callable.fn = reinterpret_cast<void (*) ()> (fn);
    320      1.1  christos     m_invoker = [] (fv_detail::erased_callable ecall, Args... args)
    321      1.1  christos       noexcept (noexcept (fn (std::forward<Args> (args)...))) -> Res
    322      1.1  christos       {
    323      1.1  christos 	auto restored_fn = reinterpret_cast<Res2 (*) (Args2...)> (ecall.fn);
    324      1.1  christos 	/* The explicit cast to Res avoids a compile error when Res is
    325      1.1  christos 	   void and the callable returns non-void.  */
    326      1.1  christos 	return (Res) restored_fn (std::forward<Args> (args)...);
    327      1.1  christos       };
    328      1.1  christos   }
    329      1.1  christos 
    330      1.1  christos   /* Storage for the erased callable.  */
    331      1.1  christos   fv_detail::erased_callable m_erased_callable;
    332      1.1  christos 
    333      1.1  christos   /* The invoker.  This is set to a capture-less lambda by one of the
    334      1.1  christos      'bind' overloads.  The lambda restores the right type of the
    335      1.1  christos      callable (which is passed as first argument), and forwards the
    336      1.1  christos      args.  */
    337      1.1  christos   Res (*m_invoker) (fv_detail::erased_callable, Args...);
    338      1.1  christos };
    339      1.1  christos 
    340      1.1  christos /* Allow comparison with NULL.  Defer the work to the in-class
    341      1.1  christos    operator bool implementation.  */
    342      1.1  christos 
    343      1.1  christos template<typename Res, typename... Args>
    344      1.1  christos constexpr inline bool
    345      1.1  christos operator== (const function_view<Res (Args...)> &f, std::nullptr_t) noexcept
    346      1.1  christos { return !static_cast<bool> (f); }
    347      1.1  christos 
    348      1.1  christos template<typename Res, typename... Args>
    349      1.1  christos constexpr inline bool
    350      1.1  christos operator== (std::nullptr_t, const function_view<Res (Args...)> &f) noexcept
    351      1.1  christos { return !static_cast<bool> (f); }
    352      1.1  christos 
    353      1.1  christos template<typename Res, typename... Args>
    354      1.1  christos constexpr inline bool
    355      1.1  christos operator!= (const function_view<Res (Args...)> &f, std::nullptr_t) noexcept
    356      1.1  christos { return static_cast<bool> (f); }
    357      1.1  christos 
    358      1.1  christos template<typename Res, typename... Args>
    359      1.1  christos constexpr inline bool
    360      1.1  christos operator!= (std::nullptr_t, const function_view<Res (Args...)> &f) noexcept
    361      1.1  christos { return static_cast<bool> (f); }
    362      1.1  christos 
    363  1.1.1.2  christos namespace fv_detail {
    364  1.1.1.2  christos 
    365  1.1.1.2  christos /* Helper traits type to automatically find the right function_view
    366  1.1.1.2  christos    type for a callable.  */
    367  1.1.1.2  christos 
    368  1.1.1.2  christos /* Use partial specialization to get access to the callable's
    369  1.1.1.2  christos    signature, for all the different callable variants.  */
    370  1.1.1.2  christos 
    371  1.1.1.2  christos template<typename>
    372  1.1.1.2  christos struct function_view_traits;
    373  1.1.1.2  christos 
    374  1.1.1.2  christos /* Main partial specialization with plain function signature type.
    375  1.1.1.2  christos    All others end up redirected here.  */
    376  1.1.1.2  christos template<typename Res, typename... Args>
    377  1.1.1.2  christos struct function_view_traits<Res (Args...)>
    378  1.1.1.2  christos {
    379  1.1.1.2  christos   using type = gdb::function_view<Res (Args...)>;
    380  1.1.1.2  christos };
    381  1.1.1.2  christos 
    382  1.1.1.2  christos /* Function pointers.  */
    383  1.1.1.2  christos template<typename Res, typename... Args>
    384  1.1.1.2  christos struct function_view_traits<Res (*) (Args...)>
    385  1.1.1.2  christos   : function_view_traits<Res (Args...)>
    386  1.1.1.2  christos {
    387  1.1.1.2  christos };
    388  1.1.1.2  christos 
    389  1.1.1.2  christos /* Function references.  */
    390  1.1.1.2  christos template<typename Res, typename... Args>
    391  1.1.1.2  christos struct function_view_traits<Res (&) (Args...)>
    392  1.1.1.2  christos   : function_view_traits<Res (Args...)>
    393  1.1.1.2  christos {
    394  1.1.1.2  christos };
    395  1.1.1.2  christos 
    396  1.1.1.2  christos /* Reference to function pointers.  */
    397  1.1.1.2  christos template<typename Res, typename... Args>
    398  1.1.1.2  christos struct function_view_traits<Res (*&) (Args...)>
    399  1.1.1.2  christos   : function_view_traits<Res (Args...)>
    400  1.1.1.2  christos {
    401  1.1.1.2  christos };
    402  1.1.1.2  christos 
    403  1.1.1.2  christos /* Reference to const function pointers.  */
    404  1.1.1.2  christos template<typename Res, typename... Args>
    405  1.1.1.2  christos struct function_view_traits<Res (* const &) (Args...)>
    406  1.1.1.2  christos   : function_view_traits<Res (Args...)>
    407  1.1.1.2  christos {
    408  1.1.1.2  christos };
    409  1.1.1.2  christos 
    410  1.1.1.2  christos /* Const member functions.  function_view doesn't support these, but
    411  1.1.1.2  christos    we need this in order to extract the type of function objects.
    412  1.1.1.2  christos    Lambdas pass here, after starting at the operator() case,
    413  1.1.1.2  christos    below.  */
    414  1.1.1.2  christos template<typename Res, typename Class, typename... Args>
    415  1.1.1.2  christos struct function_view_traits<Res (Class::*) (Args...) const>
    416  1.1.1.2  christos   : function_view_traits<Res (Args...)>
    417  1.1.1.2  christos {
    418  1.1.1.2  christos };
    419  1.1.1.2  christos 
    420  1.1.1.2  christos /* Member functions.  Ditto, for function objects with non-const
    421  1.1.1.2  christos    operator().  */
    422  1.1.1.2  christos template<typename Res, typename Class, typename... Args>
    423  1.1.1.2  christos struct function_view_traits<Res (Class::*) (Args...)>
    424  1.1.1.2  christos   : function_view_traits<Res (Args...)>
    425  1.1.1.2  christos {
    426  1.1.1.2  christos };
    427  1.1.1.2  christos 
    428  1.1.1.2  christos /* Function objects, lambdas, std::function, any type that defines
    429  1.1.1.2  christos    operator().  */
    430  1.1.1.2  christos template<typename FuncObj>
    431  1.1.1.2  christos struct function_view_traits
    432  1.1.1.2  christos   : function_view_traits <decltype
    433  1.1.1.2  christos 			  (&std::remove_reference<FuncObj>::type::operator())>
    434  1.1.1.2  christos {
    435  1.1.1.2  christos };
    436  1.1.1.2  christos 
    437  1.1.1.2  christos } /* namespace fv_detail */
    438  1.1.1.2  christos 
    439  1.1.1.2  christos /* Make a function_view from a callable.  Useful to automatically
    440  1.1.1.2  christos    deduce the function_view's template argument type.  */
    441  1.1.1.2  christos template<typename Callable>
    442  1.1.1.2  christos auto make_function_view (Callable &&callable)
    443  1.1.1.2  christos   -> typename fv_detail::function_view_traits<Callable>::type
    444  1.1.1.2  christos {
    445  1.1.1.2  christos   using fv = typename fv_detail::function_view_traits<Callable>::type;
    446  1.1.1.2  christos   return fv (std::forward<Callable> (callable));
    447  1.1.1.2  christos }
    448  1.1.1.2  christos 
    449      1.1  christos } /* namespace gdb */
    450      1.1  christos 
    451      1.1  christos #endif
    452