I am trying to use a numerical integration library that requires me to pass it a double (*f)(double,void*) as an argument. How can I pass it a lambda I create in the same scope? I tried
auto myLambda = [&](double d, void* data) { ... }
but the type of the lambda cannot be converted to the type required by the library. Is there an workaround?
Thank you for your time!
template<class T>using type=T;
template<class F>
struct callback_t {
F data;
void* pdata(){return &data;}
template<class R, class...Args>
operator type<R(*)(Args...,void*)>()const{
return [](Args...args,void*pdata)->R{
F* data=static_cast<F*>(pdata);
return (*f)(std::forward<Args>(args)...);
};
}
};
template<class F>
callback_t<F> callback(F f){
return{std::move(f)};
}
use:
int scale=3;
auto cb = callback([&](double d){return d*scale;});
then pass cb in place of the function pointer, and cb.pdata() for the void* parameter.
Presumably this library also lets you pass in the data argument with which the supplied function will be called. In that case, you can define a wrapper that treats that argument as a pointer to the actual object you want to call and forwards the call to that object, maybe something like this:
template <class F>
double function_for_library(double d, void* data) {
F& f = *static_cast<F*>(data);
return f(d);
}
Now if you have some arbitrary function object f of type F you can invoke the library like this:
invoke_library(function_for_library<F>, &f); // implicit conversion to void*
For a lambda you'll have to use decltype but it's no big deal.
auto myLambda = /* ... */;
invoke_library(function_for_library<decltype(myLambda)>, &myLambda);
Or you can write another wrapper that deduces the type.
Only lambda without capture may decay to function pointer
I suspect that void* is the way to pass user data.
so you have to create a struct
struct Functor
{
explicit Functor(capture_t&);
void operator()(double d)
{
// Your stuff
}
static void call(double d, void* userdata)
{
(*reinterpret_cast<Functor*>(userdata))(d)
}
private:
capture_t m_capture
};
And then call
Functor func(capture);
library_function(&Functor::call, &func);
Related
Let's say a I have a typedef for a specific std::function such as:
typedef std::function<int(int a, int b, int c)> func_type;
Can I reuse that typedef when defining a lambda that implements it?
For example, in the example below, the function foo accepts a func_type, but the call-site for foo needs to replicate the signature:
void foo(func_type f) {
// ...
}
int main() {
foo([](int a, int b, int c){ return a + b + c; });
}
Can I somehow re-use the func_type typedef when declaring the lambda, so I don't have to repeat the argument list (and so changes to the func_type typedef will be transparent for lambda bodies that work with the new definition).
Something like [](??? func_type ???){ return a + b + c; }.
The variable names in std::function<int(int a, int b, int c)> are not part of the type -- they are basically comments. There is no way to extract them at any other point.
So if you hope to get a, b and c you are out of luck.
One simple thing you can do is use auto:
foo( [](auto...args) { return args+...+0; } );
which is close to what you want. If you have 3 arguments you can do:
foo( [](auto a, auto b, auto c) { return a+b+c; } );
But the return type doesn't match, other than because std::function does the conversion for you.
You can extract the types of a b and c and make the lambda work differently, but not with the return type. Not unless you do something insane like:
template<class T>
struct tag_t{ contexpr tag_t(){} using type=T; };
template<class T>
constexprt tag_t<T> tag{};
template<class Tag>
using type_t = typename Tag::type;
template<class F>
struct deducer {
F f;
template<class R, class...Args>
operator std::function<R(Args...)>() const {
return f( tag<R>, tag<Args>... );
}
};
template<class F>
deducer<F> make_deducer( F f ){ return {std::move(f)}; }
int main() {
foo(make_deducer([](auto R, auto...Args){
return []( type_t<decltype(Args)>... args )->type_t<decltype(R)> {
return 0+...args;
});
}));
}
I would advise against this. But I deduced the argument types and return type of the lambda from what std::function I was passed to.
What we do here is we create a deducer type, that when converted to a std::function passes the arguments and return type expected to a lambda it stores. That lambda then generates a custom lambda for those exact arguments.
This is neither brief, simple nor sane.
If you know you have a std::function and what you want to do is defer the selection of the type arguments to std::function, you can just have a generic lambda:
foo([](auto... xs) { return (... + xs); });
Since it's std::function's call operator that drives how the lambda is called, this'll do the right thing. Of course, this requires C++14 (and the fold-expression I used above requires C++17, but that's not as important). You may or may not want to use auto&&, depending on what the types actually are.
For C++11, you can't easily do such a thing with a lambda. You'd need to fix the arity and manually list all the types. This isn't practical. You could fallback to using a normal function object, with a call operator template, but then you lose the advantages of a lambda.
A std::function is
is a general-purpose polymorphic function wrapper. Instances of
std::function can store, copy, and invoke any Callable target --
functions, lambda expressions, bind expressions, or other function
objects, as well as pointers to member functions and pointers to data
members. -- source cppreference.com
So yes, this approach is perfectly valid !
However the signature of the typedef can't be taken over to short-circuit the lambda definition.
Remark: The typedef is about the return type and the parameter types but not the parameter names, so if short-circuiting the parameter list would be legal, the body of the lambda would not know which parameters to use:
int main() {
foo([](int d, int e, int f){ return d + e + f; });
}
Assuming I have a function like the following in C++:
template<typename Container>
void doNothing(Container * container) {
for (auto element: container) {
std::cout << element;
}
}
Would it be possible to "simulate" methods on various classes that could implement this function by passing this to it instead of the first parameter. (E.g. a class like std::vector, std::string ... etc).
So basically instead of having to use it as:
std::vector<double> a{1, 2, 0.5}:
doNothing(a);
I could call it as:
std::vector<double> a{1, 2, 0.5}:
a.doNothing();
No, you can't do that.
The this parameter in the call a.b() is implicit, and there's no way to fake an implicit parameter.
The a.b() syntax is simply not available to you unless b is a member.
You can always simulate a member function by passing the this pointer of an object.
After all, that's all the compiler is doing for proper member functions (passing this as a hidden first parameter).
So, if you want a function foo to behave like a member and operate on an object (ignoring private/protected here) of type Bar, then you could declare it as:
void foo(Bar* self);
and call it like
Bar b;
foo(&b);
(or from inside a Bar member: foo(this);)
then it would be able to access members of b and call its functions by dereferencing the self pointer.
template<class F>
struct poly_mem_ptr_t{
F f;
template<class T>
friend auto operator->*( T* t, poly_mem_ptr_t self )const{
return
[t, f=self.f](auto&&...args)->decltype(auto){
return f(t, decltype(args)(args)...);
};
}
template<class T>
friend auto operator->*( T& t, poly_mem_ptr_t self )const{
return std::addressof(t)->*self;
}
};
template<class F>
poly_mem_ptr_t<F> poly_mem_ptr(F f){ return {std::move(f)}; }
Sample use:
auto do_nothing = poly_mem_ptr([](auto* ptr){ doNothing(ptr); });
std::vector<int> v={1,2,3};
(v->*do_nothing)();
not exactly what you want, but close.
As a benefit, you can add
template<class...Ts>
friend decltype(auto) operator->*( std::variant<Ts...>& var, poly_mem_ptr_t self )const{
return [&var, f=self.f](auto&&...args) {
return std::visit( [&](auto&&t)->decltype(auto){
return f( decltype(t)(t), decltype(args)(args)... );
}, var);
};
}
and now you can take a std::variant and use these poly_mem_ptrs as visitors.
With a bit of work you can also tool up an augmented std::any to support a fixed set of poly_mem_ptrs.
I am looking for a way to convert function object to function pointer.
Captureless lambda has implicit conversion that allows to:
using fptr_t = int (*)(int);
fptr_t ptr = nullptr;
ptr = [](int) { return 2; };
ptr = [](auto) { return 3; };
(*ptr)(42);
I try to do the same with old-fashioned, empty class function objects like:
struct Foo {
int operator()(int) const { return 5; }
} foo;
Or std predicates like std::less<int>.
One way I found is to wrap call of foo with lambda.
If I can assure that foo is stateless and const
I dont really need this ptr and lambda-capture:
template <typename R, typename... Args>
struct to_function_pointer<R(Args...)> {
private:
template <typename T, REQUIRES(std::is_empty<T>::value)>
static T const& stateless_const() {
return (*static_cast<T const*>(nullptr));
}
public:
using pointer = R (*)(Args...);
template <typename U>
pointer operator()(U) const {
return [](Args... args) {
return stateless_const<std::decay_t<U>>()(args...);
};
}
};
But here I do not know how to provide perfect forwarding,
cause [](Args&&...) or [](auto&&...) cannot convert to R(*)(Args...).
Such trick fails when args is noncopyable like std::unique_ptr<int>.
I know that I could use std::function, but it's kind of heavy-weight, while I am trying to get a light-weight solution.
Live example.
Any advice appreciated.
I believe you can simplify your to_function_pointer with just:
template <typename R, typename... Args>
struct to_function_pointer<R(Args...)> {
using pointer = R(*)(Args...);
template <typename U, REQUIRES(std::is_empty<U>::value && std::is_trivially_constructible<U>::value)>
pointer operator()(U ) const
{
return [](Args... args) {
return U{}(std::forward<Args>(args)...);
}
}
};
Few things to note. Args... will already be references or not, you're providing that signature. So forward<> will still do the same thing - the function just happens to not be a template here. Also, scrap the weird nullptr cast. That just looks bad - if we just require trivial constructibility we can just write U{} which seems way cleaner to me.
I am writing a wrapper class for callable types (pointer to function, functors, etc). I want to implement something like std::function.
I define constructor from pointer to function:
template <typename Ret, typename... Args>
class function<Ret(Args...)>
{
public:
function(Ret (func)(Args...))
{
m_fn_ptr = func;
}
}
Now, let's assume that i want to use my class like this:
int int_function(int n)
{
return n;
}
function<int(short)> wrapper(&int_function); // compile error
Despite that short are implicit convertable to int compiler cannot deduce template parameters and call appropriate constructor.
Then i tried this:
template <typename FRet, typename... FArgs>
function(FRet (func)(FArgs...))
{
m_fn_ptr = static_cast<Ret (*f)(Args...)>(func);
}
But I got invalid static cast.
How can I fix that ?
The super_func is a function object with no state that can convert to any compatible call signature.
template<class T>using type=T;
template<class Sig, Sig* func>
struct super_func;
template<class R, class...Args, R(*func)(Args...)>
struct super_func<R(Args...), func> {
using Sig = R(Args...);
using pSig = Sig*;
template<class R2, class...Args2, std::enable_if_t<
std::is_convertible<
std::result_of_t<pSig(Args2...)>,
R2
>{}
&& !std::is_same<R2, void>{},
bool
> =true>
constexpr operator type<R2(Args2...)>*() const {
return [](Args2...args)->R2{
return func(std::forward<Args2>(args)...);
};
}
template<class...Args2, std::enable_if_t<
std::is_same<
std::result_of_t<pSig(Args2...)>,
R
>{},
bool
> =true>
constexpr operator type<void(Args2...)>*() const {
return [](Args2...args)->void{
func(std::forward<Args2>(args)...);
};
}
constexpr operator pSig() const {
return func;
}
constexpr R operator()(Args...args)const{
return func(std::forward<Args>(args)...);
}
};
live example. A super_func is stateless. To use it on a function foo, do:
super_func< decltype(foo), &foo > super_foo;
and you get a callable stateless empty object which behaves a lot like foo does, except you can assign it to a pointer to any compatible function pointer and it generates it "on the fly" at compile time.
A super_foo can be fed to your function object.
Doing this on the fly doesn't work without the exterior help, as we need the foo to be a truly static bit of information. By the time it becomes a variable, it is too late to do this statelessly, so we cannot use the lambda trick (without an extra pvoid) to generate a function pointer for the exact signature we want.
You could do a macro:
#define SUPER(X) super_func< decltype(X), &X >{}
and then create your function object with function<double()> f(SUPER(foo));
Another approach is to store an extra pointer's worth of state, and create "the fastest possible delegate" style type erasure. (that term can be googled for one of many implementations, each faster than the last).
How can I fix that ?
Use the correct types when creating wrapper.
Instead of using
function<int(short)> wrapper(&int_function);
use
function<int(int)> wrapper(&int_function);
Remember that class templates instantiated with int and short are very different types and are not convertible to each other.
template <typename T> struct Foo {};
Foo<int> a;
Foo<short> b = a; // Not OK.
Foo<short> c;
Foo<int> d = c; // Not OK.
Your function constructor expects a pointer to a function that takes a short, not an int. The fix is to provide it such a function. The easiest way to do that is to use a lambda with an empty capture-list, that is implicitly convertible to a function pointer:
function<int(short)> wrapper( [](short s) { return int_function(s); } );
I've been trying to come up with a templated function that generalizes the bounce procedure when dealing with C APIs that use function pointer callbacks.
I've mostly figured it out and have a working system, but I'm wondering if there is a way to clean up the final step.
Imagine you have an API that takes a function pointer and a user data pointer. You want to use an instance method as the callback target. This requires a "bounce" function that reinterprets the user data pointer as an instance pointer and calls the method with the rest of the arguments.
The following example code works:
#include <cstdio>
class Foo {
public:
Foo(int val) : val_(val) { }
void baz(int v) const
{
printf("baz %d\n", v + val_);
}
private:
int val_;
};
// Templated bounce function
template<class T, class Method, Method m, class Ret, class ...Args>
static Ret bounce(void *priv, Args... args)
{
return ((*reinterpret_cast<T *>(priv)).*m)(args...);
}
#define BOUNCE(c, m) bounce<c, decltype(&c::m), &c::m>
// Callback simulator
void call_callback(void (*func)(void *, int), void *priv, int v)
{
if (func) {
func(priv, v);
}
}
// Main Entry
int main()
{
Foo bar(13);
call_callback(&bounce<Foo, decltype(&Foo::baz), &Foo::baz>, &bar, 10);
call_callback(&BOUNCE(Foo, baz), &bar, 11);
return 0;
}
Basically I'm looking for a way to clean up the usage. The macro works but I'm trying to instead find some type of helper function that can just take a method pointer parameter like &Foo::baz and deduce all the parameters. Something like a bounce_gen(&Foo::baz) that would return a pointer to the actual bounce function.
It has been a fun exercise, but I can't quite get the last piece.
The type of a member function pointer contains the class type and the function signature. So, you can let template function argument deduction handle this for you:
template<class T, class Method, class ...Args>
static auto bounce(Method T::*func, T* priv, Args... args) -> decltype((priv->*m)(args...))
{
return (priv->*m)(args...);
}
More convenient might be to either use std::bind or a lambda to completely hide the fact that it is a member function call:
template<class Func, class ...Args>
static auto bounceCallable(Func func, Args... args) -> decltype(func(args...))
{
return func(args...);
}
And you would call it like this:
call_callback([&bar](int v){bar.baz(v);}, 11);
With a lambda, you have a syntax nicer than with std::bind, but it comes at the cost of having to repeat the signature.