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);
}
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.