I want to use the pthreads library in C++ with C++ lambdas. My lambdas are of the type std::function<void(X)> when X can be any type such as int, double, float or a custom type. Moreover, it is possible that the lambda accepts more than one parameter. For example, I can have a lambda of the type std::function<void(float,int)>. Now I want to cast this lambda to a C style function pointer which takes in a single void* arguments and returns a void* type. So I want to cast my lambda to a function pointer of the type void* (*)(void*).
I want to do this so that I can pass this function pointer to the pthread_create API. Can someone please tell me how can I do this?
I think that since the target type accepts a void* argument, I'll need to create a wrapper function of the type void* my_wrapper(void*) which would call the lambda inside its body. Then I think I should be able to pass a pointer to the wrapper to the pthreads API.
Moreover, I will also need a way to capture the lambda arguments so that I can wrap them up in a custom structure whose pointer I can then pass to the wrapper.
Start by creating a lambda, callable without parameters and returning void *. Presumably it'd call your std::function with an appropriate parameter.
auto lambda = [&]() -> void *
{
std::cout << "Hello, world!\n";
return nullptr;
};
Then create another lambda:
auto caller = [](void *data) -> void *
{
return (*static_cast<decltype(lambda) *>(data))();
};
caller(&lambda) calls lambda().
Now you can pass caller to pthread_create, with &lambda as the argument.
Related
I want to make a C++ assembly hooking using lambda captures but for this i need to get the pointer of a lambda capture function.
something like this:
int val0 = 42;
auto lambdaCap = new auto([&]() -> int { return val0++; });
uint64_t pLambdaFn = static_cast<uint64_t>(&decltype(*lambdaCap)::operator()); // need this
I understand than a lambda function capture seems like an instance of class with a functor, but i want get the static address of lambda::operator(). In memory "lambdaCap" is just a ptr to the variables members used in the lambda.
Thanks
&decltype(*lambdaCap)::operator()) is not valid because decltype(*lambdaCap) is actually an lvalue reference to the closure type.
Instead, std::remove_pointer_t<decltype(lambdaCap)> would give you the closure type itself. So you can write &std::remove_pointer_t<decltype(lambdaCap)>::operator() to get the pointer-to-member-function corresponding to the closure type's function call operator.
However, this expression has type int (T::*)(), which cannot be converted into an integer type. You can store it as-is, and call it using a pointer to an instance of the closure type (such as lambdaCap itself) but you can't convert it to uint64_t. There is no way to convert a pointer-to-nonstatic-member to an integer type, whether with static_cast or reinterpret_cast or any other cast.
I'd like to build a C++ library which is usable from C as well.
This is the header file I want to be able to compile in C:
typedef void (*log_function_t)(const char *);
typedef void (*delay_function_callback_t)(uint32_t);
typedef void (*delay_function_t)(uint32_t, delay_function_callback_t);
extern "C" void core_init(log_function_t logFunction, delay_function_t delayFunction);
However, since I'm writing the library in C++, it would be nice to work with std::function objects instead of function pointers, so I'd like to call functions like this:
using LogFunction = std::function<void(const char*)>;
using DelayFunctionCallback = std::function<void(uint32_t)>;
using DelayFunction = std::function<void(uint32_t, DelayFunctionCallback)>;
void setLogFunction(const LogFunction& logFunction);
void setDelayFunction(const DelayFunction& delayFunction);
Calling the setLogFunction works just fine, but when I try to call setDelayFunctionit doesn't work.
void core_init(log_function_t logFunction, delay_function_t delayFunction)
{
Utility::getInstance().setLogFunction(logFunction);
Utility::getInstance().setDelayFunction(delayFunction);
}
It says: Reference to type 'const DelayFunction' (aka 'const function<void (unsigned int, function<void (unsigned int)>)>') could not bind to an lvalue of type 'delay_function_t' (aka 'void(*)(unsigned int, void (*)(unsigned int))')
Obviously I understand why it doesn't work, but I have a feeling that it should be possible to solve and I'm just not experienced enough to solve it.
What you're asking seem to be passing a function pointer from C to C++ where the function takes a std::function as argument. I'm afraid this is not possible just as C can't pass a function pointer that takes a std::vector as argument.
When calling Utility::getInstance().setDelayFunction(delayFunction), the ctor of a specialized std::function (i.e. DelayFunction) is matched to construct from a function pointer. However, the match fails because the ctor (of DelayFunction) accepts as its 2nd argument a specialized std::function (i.e. DelayFunctionCallback) , rather than a function pointer (i.e. delay_function_callback_t).
I think the problem lies in the implementation of std::function, which encapsulates the function pointer and erases the latter's type. (See How is std::function implemented?) As a result, a C++ std::function is a different type than a plain-C function pointer.
To workaround this, you could relax the C++-ishness a bit and declare DelayFunction as accepting void(*)(unsigned) instead. I.e., in the C++ file:
using LogFunction = std::function<void(const char*)>;
using DelayFunction = std::function<void(unsigned, delay_function_callback_t)>;
// ^^^^^^^^^^^^^^^^^^^^^^^^^
EDIT: Re. the comment on calling the DelayFunction object from C++, instead of passing a lamba function as the callback (which would fail with the workaround above, since the lambda function can only construct a DelayFunctionCallback, not a delay_function_callback_t), it might be easier to implement the callback as a static member function and use it directly:
Utility::getInstance().delay(delay, (delay_function_callback_t)&Utility::next);
BTW, if Utility is going to store the std::function objects internally, then it may be more efficient to pass-by-value, since the LogFunction and DelayFunction objects will always be constructed anyway (i.e. they are rvalue in core_init).
A void(*)() is fundamentally different from a std::function<void()>.
You can get closer with a void(*)( void* ), void*; a std function has both callable-ness and state, a function pointer only has callable-ness. (std function also carries RTTI and how-to-cleanup-state and how-to-copy-state).
Now you can convert a void(*)() into a std function that is stronger; but not the other way. And the arguments to a function are converted the other way when the call happens.
struct callback {
void* state;
void(*action)(int32_t);
void(*cleanup)(void*);
void*(*copy)(void*);
};
that is the rough C equivalent of a std::function<void(int32_t)>.
The result of an std::bind can be assigned to an std::function
A function pointer can be assigned to an std::function.
So far I was under the impression std::function can generally hold any function pointer. And anything an std::function can hold can be assigned to a function pointer.
And found that the reult of an std::bind can't be assigned to a function pointer
int add(int x, int y)
{
return x+y;
}
int main()
{
std::function<int (int, int)> fp = &add; // a func pointor can be assined to an std::function
int result = fp(3,5) // this works fine
std::function<int (int, int)> add_v2 = std::bind(&add, _1,_2); // std:: bind can be assigned to an std::function
int result = add_v2(3,5); // works fine
int (*add_v3)(int, int);
add_v3 = std::bind(&add, _1,_2); // does not compile
}
Can you please explain why I can't assign the result of std::bind to a function pointr
std::function knows how to invoke calls to multiple callable types, including plain functions, lambdas, and the result of std::bind(). Just because std::function can handle multiple callable types does not means the individual types are interchangeable/assignable with each other.
The return value of std::bind() returns a callable object of an unspecified type determined by the implementation. That type has an operator() that std::function calls. The bound object carries state information about the target object and class method it needs to call inside its operator(). So, by definition, such an object could never be assignable to a plain function pointer. There would be nowhere to store the state data, or even the bound object's own this pointer. The same reasons why a capturing lambda cannot be assigned to a plain function pointer, either.
add_v3 = std::bind(&add, _1,_2); // does not compile
As just the most obvious reason this can't be made to work, consider that all that's left after this line of code executes is a naked pointer. What can it point to?
The resulting bound function (the result of binding add to _1 and _2) clearly didn't exist before this line of code executes. And whatever std::bind created, it's a temporary that will no longer exist after this line executes.
So what could add_v3, a simple raw pointer, possibly point to? What would own it? What would manage its lifetime? When would it be destroyed?
My code (C++) need to pass lambda as function pointer. My lambdas always: a) return void; b) never takes any parameter; and c) can have zero or more capture arguments. I want to pass this lambda as a function pointer but unable to do so. Any advice ?
Sample code:
void fptrfunc(void (*fptr)()){
fptr();
}
int main(){
int x = 2;
fptrfunc([](){cout << "LAMBDA CALL--1"<< endl; }); // Works
fptrfunc([x](){cout << "LAMBDA CALL--2"<< endl; }); // Does not compile
return 0;
}
Lambda functions which are really just functions, i.e., don't carry and data, can be converted to function pointers. To not have any data clearly the capture has to be empty. The other parts of the signature do't matter: as long as the types match, you can assign a lambda function [with an empty capture] to a function pointer.
The moment you need to have data with your lambda function you won't be able to convert it to a function pointer because there is no place to store the additional data. If you have a sensible interface where you need to pass the lambda function you may have some user data being passed along, often a void*. You could a combination of an auxiliary function pointer and a lambda, probably wrapped by a suitable std::function<Sig>, pointed to by the user data to still call a lambda function.
What you want, is not possible in C++. Lambdas that capture variables are not convertible to a function pointer.
You need to do drop the requirement c) and only use lambdas without captures. Or you must change the declaration of fptrfunc. You can change the parameter type to std::function or make it a template that can accept any type of functor that implements the operator().
Since my last recent question was unfortunately worded and resulted in a solution to another problem then mine, here I will try to formulate my actual problem in a clear way.
Before we start, as a sidenote, I am integrating the Javascript Engine V8 into my C++ application. That's where all the types in the example come from. And that's also the reason for the fact that I need a raw function pointer in the end. But I elaborate on this below.
From inside a class I need to pass a lambda expression with the capture clause [=] as parameter of the type std::function to another function and cast it to a raw function pointer there.
In this code, InvocationCallback is simply a typedef for a function with the signature Handle<Value>(Arguments const &).
typedef Handle<Value> (*InvocationCallback)(Arguments const &);
void Bind(string Name, function<Handle<Value>(Arguments const &)> Function)
{
InvocationCallback* function = Function.target<InvocationCallback>();
}
All the lambda expressions have the same signature, too. Note that Handle<String> is compatible to Handle<Value> in this example. It's given by the Javascript Engine V8, too.
Bind("name", [=](const Arguments& args) -> Handle<Value>{
Handle<String> result = String::New(Name().c_str());
return result;
});
C++ allows me to pass this lambda as std::function to the function above. But I guess a lambda expression also stores a reference to object it refers. Somehow the access specified by [=] must be realized. That might be the reasons that casting the std::function to a raw function pointer fails.
InvocationCallback* function = Function.target<InvocationCallback>();
There is neither a compile time error nor a runtime error but the debugger tells me that it results in a null pointer. But I need the raw function pointer for further processing. I guess I could convert the lambda after std::binding the reference or this-pointer first.
Update: Since it seems to be impossible to get the state out of the lambda, this is what I tried. It compiles but function come out to be a null pointer.
Bind("name", this, [](Base* object, const Arguments& args) -> Handle<Value>{
return v8::String::New(((Derived*)object)->Name().c_str());
});
void Bind(string Name, Module *Object, function<Handle<Value>(Module*, Arguments const &)> Function)
{
function<Handle<Value>(Arguments const &)> method = std::bind(Function, Object, std::placeholders::_1);
InvocationCallback* function = method.target<InvocationCallback>();
}
You can't, because a lambda which captures is a closure, so it has state (it is an object with instance variables). A function pointer has no state. Thus, you cannot do this without either 1) the API you are using that requires the function pointer also allows you to pass a user data argument where you pass the state, or 2) storing the state in a global variable or something.
Search around Stack Overflow for "member function to callback" and you will get an idea (basically, you are wanting to use a member function, the operator(), as a callback).
You can convert a capturing lambda/functor into a function pointer, but you need to be careful when doing it:
https://codereview.stackexchange.com/questions/79612/c-ifying-a-capturing-lambda