mirror of
https://github.com/bminor/binutils-gdb.git
synced 2025-11-16 12:34:43 +00:00
Compare commits
1 Commits
binutils-2
...
users/palv
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
37c2487312 |
@@ -61,7 +61,7 @@ struct plus_one_int_func_obj
|
||||
};
|
||||
|
||||
static void
|
||||
run_tests ()
|
||||
test_function_view ()
|
||||
{
|
||||
/* A simple lambda. */
|
||||
auto plus_one_lambda = [] (int val) { return ++val; };
|
||||
@@ -168,6 +168,86 @@ run_tests ()
|
||||
SELF_CHECK (!check_op_eq_null);
|
||||
}
|
||||
|
||||
/* A template function where the function_view type is dependent on a
|
||||
template parameter. */
|
||||
|
||||
template<typename T>
|
||||
static int
|
||||
tmpl_func (T val, gdb::function_view<T (T)> callback)
|
||||
{
|
||||
return callback (val) + 1;
|
||||
}
|
||||
|
||||
static int
|
||||
make_fv_test_func (int val)
|
||||
{
|
||||
return val + 1;
|
||||
}
|
||||
|
||||
/* A function object with const operator(). */
|
||||
|
||||
struct func_obj_const_op
|
||||
{
|
||||
int operator() (int val) const
|
||||
{
|
||||
return val + 1;
|
||||
}
|
||||
};
|
||||
|
||||
/* A function object with non-const operator(). */
|
||||
|
||||
struct func_obj_non_const_op
|
||||
{
|
||||
int operator() (int val)
|
||||
{
|
||||
return val + 1;
|
||||
}
|
||||
};
|
||||
|
||||
static void
|
||||
test_make_function_view ()
|
||||
{
|
||||
/* Function reference. */
|
||||
SELF_CHECK (3 == tmpl_func (1, gdb::make_function_view (make_fv_test_func)));
|
||||
|
||||
/* Function pointer. */
|
||||
SELF_CHECK (3 == tmpl_func (1, gdb::make_function_view (&make_fv_test_func)));
|
||||
|
||||
/* Reference to const and non-const function pointers. */
|
||||
typedef int (*func_ptr) (int);
|
||||
func_ptr ptr = make_fv_test_func;
|
||||
const func_ptr cptr = make_fv_test_func;
|
||||
SELF_CHECK (3 == tmpl_func (1, gdb::make_function_view (ptr)));
|
||||
SELF_CHECK (3 == tmpl_func (1, gdb::make_function_view (cptr)));
|
||||
|
||||
/* Lambdas. */
|
||||
|
||||
auto lambda = [] (int val) -> int { return val + 1; };
|
||||
|
||||
/* This wouldn't compile, since tmpl_func is a template and its
|
||||
function_view argument's callable type is a dependent type. The
|
||||
passed argument must be of the exact type of the function's
|
||||
parameter. */
|
||||
// SELF_CHECK (3 == tmpl_func (1, lambda));
|
||||
|
||||
SELF_CHECK (3 == tmpl_func (1, gdb::make_function_view (lambda)));
|
||||
|
||||
/* Regular function objects. */
|
||||
|
||||
func_obj_non_const_op fobj;
|
||||
SELF_CHECK (3 == tmpl_func (1, gdb::make_function_view (fobj)));
|
||||
|
||||
func_obj_const_op cfobj;
|
||||
SELF_CHECK (3 == tmpl_func (1, gdb::make_function_view (cfobj)));
|
||||
}
|
||||
|
||||
static void
|
||||
run_tests ()
|
||||
{
|
||||
test_function_view ();
|
||||
test_make_function_view ();
|
||||
}
|
||||
|
||||
} /* namespace function_view */
|
||||
} /* namespace selftests */
|
||||
|
||||
|
||||
@@ -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<typename T>
|
||||
void my_function (T v, gdb::function_view<void(T)> 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<void(int)> 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<void(int)> 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<Res (Args...)> &f) noexcept
|
||||
{ return static_cast<bool> (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<typename>
|
||||
struct function_view_traits;
|
||||
|
||||
/* Main partial specialization with plain function signature type.
|
||||
All others end up redirected here. */
|
||||
template<typename Res, typename... Args>
|
||||
struct function_view_traits<Res (Args...)>
|
||||
{
|
||||
using type = gdb::function_view<Res (Args...)>;
|
||||
};
|
||||
|
||||
/* Function pointers. */
|
||||
template<typename Res, typename... Args>
|
||||
struct function_view_traits<Res (*) (Args...)>
|
||||
: function_view_traits<Res (Args...)>
|
||||
{
|
||||
};
|
||||
|
||||
/* Function references. */
|
||||
template<typename Res, typename... Args>
|
||||
struct function_view_traits<Res (&) (Args...)>
|
||||
: function_view_traits<Res (Args...)>
|
||||
{
|
||||
};
|
||||
|
||||
/* Reference to function pointers. */
|
||||
template<typename Res, typename... Args>
|
||||
struct function_view_traits<Res (*&) (Args...)>
|
||||
: function_view_traits<Res (Args...)>
|
||||
{
|
||||
};
|
||||
|
||||
/* Reference to const function pointers. */
|
||||
template<typename Res, typename... Args>
|
||||
struct function_view_traits<Res (* const &) (Args...)>
|
||||
: function_view_traits<Res (Args...)>
|
||||
{
|
||||
};
|
||||
|
||||
/* 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<typename Res, typename Class, typename... Args>
|
||||
struct function_view_traits<Res (Class::*) (Args...) const>
|
||||
: function_view_traits<Res (Args...)>
|
||||
{
|
||||
};
|
||||
|
||||
/* Member functions. Ditto, for function objects with non-const
|
||||
operator(). */
|
||||
template<typename Res, typename Class, typename... Args>
|
||||
struct function_view_traits<Res (Class::*) (Args...)>
|
||||
: function_view_traits<Res (Args...)>
|
||||
{
|
||||
};
|
||||
|
||||
/* Function objects, lambdas, std::function, any type that defines
|
||||
operator(). */
|
||||
template<typename FuncObj>
|
||||
struct function_view_traits
|
||||
: function_view_traits <decltype
|
||||
(&std::remove_reference<FuncObj>::type::operator())>
|
||||
{
|
||||
};
|
||||
|
||||
} /* namespace fv_detail */
|
||||
|
||||
/* Make a function_view from a callable. Useful to automatically
|
||||
deduce the function_view's template argument type. */
|
||||
template<typename Callable>
|
||||
auto make_function_view (Callable &&callable)
|
||||
-> typename fv_detail::function_view_traits<Callable>::type
|
||||
{
|
||||
using fv = typename fv_detail::function_view_traits<Callable>::type;
|
||||
return fv (std::forward<Callable> (callable));
|
||||
}
|
||||
|
||||
} /* namespace gdb */
|
||||
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user