I am trying to implement a parallel runtime using argobots api.
In the main.cpp I am using a lambda function which is argument to the "kernel" function in lib.cpp. I need to convert the lambda received in lib.hpp to a function pointer and call "lib_kernel" in lib.c. I have read many answers and came to know that converting lambdas (capture by reference) to function pointer is not possible. Is there any alternative?. I also don't have any idea how deal with the template parameter T in the "kernel" function. Please help.
// main.cpp
#include "lib.hpp"
int main(int argc, char **argv) {
int result;
lib::kernel([&]() {
result = fib(10);
});
cout << "Fib(10) = " << result << "\n";
// fib is parallel implementation of fibonacci
// similar to passing function pointers to threads
}
// lib.hpp
namespace lib {
void kernel(T &&lambda) {
// T is template argument
// Need to convert lambda to function pointer
// ie. lib_kernel(fptr, args)
// Here fptr and args are received from lambda
// ie. fptr will be fib function
// args is value 10.
}
}
// lib.c
typedef void (*fork_t)(void* args);
void lib_kernel(fork_t fptr, void* args) {
fptr(args);
}
CodePudding user response:
Pass the address of the capturing lambda into the second parameter (void *
). Make a second (non-capturing) lambda to call it:
#include <iostream>
void foo(void (*func)(void *), void *arg)
{
func(arg);
}
int main()
{
int var = 42;
auto lambda = [&]{std::cout << var << '\n';};
foo([](void *f){(*(decltype(lambda) *)f)();}, &lambda);
}
CodePudding user response:
You can convert a lambda to a function pointer with
, i.e.:
typedef void (*func)(void* args);
void kernel(func fn, void* args){
fn(args);
}
void CallKernelWithLambda() {
func f = [](void*) { };
kernel(f, nullptr);
}
However, lambdas that capture cannot be converted to a function pointer -- the following fails to compile:
typedef void (*func)(void* args);
void kernel(func fn, void* args){
fn(args);
}
void CallKernelWithLambda() {
int value = 0;
func f = [&](void*) { value; };
kernel(f, nullptr);
}
You need to put the value that you want to capture in static storage or global scope, e.g.:
typedef void (*func)(void* args);
void kernel(func fn, void* args){
fn(args);
}
int value = 0;
void CallKernelWithLambda() {
func f = [](void*) { value; };
kernel(f, nullptr);
}
Putting the call to kernel
inside of a templated function doesn't make any difference, i.e.:
typedef void (*func)(void* args);
void kernel(func fn, void* args){
fn(args);
}
template <typename T>
void CallKernelWithTemplateArgumentLambda(T&& lambda) {
kernel( lambda, nullptr);
}
int value = 0;
void CallKernelWithLambda() {
CallKernelWithTemplateArgumentLambda([](void*) { value; });
}
behaves the same way as the previous snippet.