C++ lambda as templated parameter of a function not working - c++

I'm trying to pass a lambda into a parameter in the maybe() function, which is working strangely. Code is below:
template<typename R, typename F>
void maybe(R& result, F& lambda) {
if (0 == result) {
result = lambda();
}
}
auto l = [&]() {
return adi_uart_Open(deviceNum, ADI_UART_DIR_BIDIRECTION, &memory, ADI_UART_BIDIR_DMA_MEMORY_SIZE, &handle);
};
If I call
maybe(result, l);
then everything works just fine. However, if I put the lamba into the function directly, like:
maybe(result, [&](){return adi_uart_Open(deviceNum, ADI_UART_DIR_BIDIRECTION, &memory, ADI_UART_BIDIR_DMA_MEMORY_SIZE, &handle);});
then I get the following error:
error: no instance of function template "maybe" matches the argument list
I'd use std::function instead of templates, but it's not available on the embedded device i'm working on.

maybe takes an lvalue reference:
maybe(R& result, F& lambda)
C++ forbids a non-const lvalue reference to be bound to a temporary. Add a const.
maybe(R& result, F const& lambda)

Related

C++ lambda as std::function in template function

Let's say we have this simplified version of my code:
template<typename R>
R Context::executeTransient(std::function<R(VkCommandBuffer)> const &commands) {
...
R result = commands(commandBuffer);
...
return result;
}
I tried to pass a lambda function as a parameter to the function Context::executeTransient() but it works only if I explicitly assign the lambda to a specific std::function type. This works:
std::function<int(VkCommandBuffer)> f = [](VkCommandBuffer commandBuffer) {
printf("Test execution");
return 1;
};
context.executeTransient(f);
The example above works but I'd like to achieve the example below because of aesthetic reasons and don't know if this is even possible:
context.executeTransient([](VkCommandBuffer commandBuffer) {
printf("Test execution");
return 1;
});
My only requirement is that Context::executeTransient() should accept lambdas and functions with a templated return type and input argument with some specific type e.g. VkCommandBuffer.
What about simply as follows ?
template <typename F>
auto Context::executeTransient (F const & commands) {
...
auto result = commands(commandBuffer);
...
return result;
}
This way your method accept both standard functions and lambdas (without converting them to standard functions, that is preferable, from the performance point of view (as far as I know)) and the return type is deduced from the use (auto).
In you need to know the R type inside the method, you can apply decltype() to result
auto result = commands(commandBuffer);
using R = decltype(result);
If you need to know the R type as template parameter of the method, its a little more complex because involve std::declval() and, unfortunately, add redundancy
template <typename F,
typename R = decltype(std::declval<F const &>()(commandBuffer))>
R Context::executeTransient (F const & commands) {
...
R result = commands(commandBuffer);
...
return result;
}

properly forward a parameter pack in a lambda without discarding qualifiers

I am trying to store lambda functions in a queue to execute them later. In order to do that, i am trying to hide the parameter pack in a lambda without losing scope so I can still access the passed arguments in an upper scope.
Sadly I cannot compile this since the parameter pack does not match the const qualifier.
I hope it is easier to understand what I am trying to accomplish by looking at the following code. (I am using c++17, not c++20).
I think I misunderstand how to properly forward the variadic parameter pack since as I do it right now, the binding reference to const will discard qualifiers.
It is sadly not an option to expect the parameters in the functional lambda to be const.
std::queue<std::function<void()>> fcts;
template<typename F >
auto push_fct(F &task) -> void {
// Do things
fcts.push(std::move(std::function<void()>(task)));
}
template<typename F, typename... A>
auto push_fct(F& task , A&... args) -> void {
push_fct( [task, args...] { task(args...);});
}
auto main() -> int {
auto functional = [&](class_a & a, class_b & b) {
a.memberFct();
b.memberFunction(123);
}
class_a instance_a;
class_b instance_b;
push_fct(functional, instance_a, instance_b);
return 0;
}
What happens is, here [task, args...] the references are lost; task, args... are captured by value, which, in a non-mutable lambda additionally become const, which subsequently can't bind to non-const references in the call to [&](class_a & a, class_b & b).
You can capture the references by reference. Don't worry about their lifetime - the references are collapsed, and the original ones will be captured (source).
template<typename F>
auto push_fct(F&& task) -> void {
// Do things
fcts.emplace(std::forward<F>(task));
}
template<typename F, typename... A>
auto push_fct(F& task, A&... args) -> void {
push_fct([&task, &args...]{ task(args...); });
}

template function pointers and lambdas

Hi I'm trying to sort out an issue with the following code:
template<typename... Args>
using Func = void (*)(Args... args);
template<typename... Args>
void do_test(Func<Args&...> f, Args&... args) {
for (int i = 0; i != 100; i++)
f(args...);
}
int main(){
int x = 0;
do_test(Func<int&>([](int &y) { y++; }), x); // OK
// Error - mismatched types 'void (*)(Args& ...)' and 'main()::<lambda(int&)>'
do_test([](int &y) { y++; }, x);
return x;
}
https://godbolt.org/z/UaXxFJ
Can anyone explain why it is necessary to wrap the lambda in Func<int&>( )? Is there a way to avoid it? - because if the argument list is non-trivial it becomes quite tedious having to list out the argument types twice.
The goal here is to make a visitor pattern that the compiler can optimize away. I'm using it for an image processing algorithm where I want to reuse the code of the outer loops, with various bits of inner code. The Args are being used as something similar to a lambda capture, except using traditional function pointers so that the compiler can optimize them away - which it seems not to be able to do with std::function<>
You can just allow the function to take any type, whether function pointer or lambda:
template<typename F, typename... Args>
void do_test(F f, Args&... args) {
for (int i = 0; i != 100; i++)
f(args...);
}
Depending on your use case, consider taking f by-const-reference or forwarding reference (i.e. F&&), as well.
You should also consider changing the way you take the args function parameters. Usually in such a situation you would take them by forwarding reference, meaning Args&&... args instead of Args&... args. Otherwise you won't be able to call the function with rvalues arguments.
Or if you have some specific reason to accept only this one specific function pointer type, you can make the first function parameter a non-deduced context, given that the template arguments can already be deduced from the other function parameters:
template<typename... Args>
void do_test(std::type_identity_t<Func<Args&...>> f, Args&... args) {
for (int i = 0; i != 100; i++)
f(args...);
}
std::type_identity_t is a C++20 feature, but can be easily implemented:
template<typename T>
struct type_identity {
using type = T;
};
template<typename T>
using type_identity_t = typename type_identity<T>::type;
Everything left to the scope resolution operator :: in type_identity<T>::type is a non-deduced context and so the first function parameter will not be used to deduce the Args, which in turn means that implicit conversions will be considered (e.g. the lambda to function pointer conversion).
Alternatively, as mentioned by #FrançoisAndrieux in the question comments, you can use the lambda + trick to convert the lambda to a function pointer at the call site:
do_test(+[](int &y) { y++; }, x);
Also note that taking a function pointer of this specific type means that the function can only be called with functions that have exactly this type. For example args is always deduced to a reference type, so any possible function than may be used with this one must take only reference parameters. This is usually not what you want. Usually you want the loose behavior of std::function<R(Args...)>, which can be constructed from any function object that is callable with the specified Args and returns something that can be implicitly converted to R.

obtain function pointer of bound/inferred capturing lambda with static local variable

Is it possible to obtain a C style function pointer of a capturing lambda using static local variables?
I am trying to bind the first the argument of the derived function to the original parameter
template <typename F>
class entry_hook
{
public:
entry_hook(void* original, F&& hook)
{
static auto bound = [&](auto&&... args)
{
return hook(original, std::forward<decltype(args)>(args)...);
};
auto* function_ptr = +[](auto&&... args) // -> decltype(bound(std::forward<decltype(args)>(args)...))
{
return bound(std::forward<decltype(args)>(args)...);
};
}
};
Using:
const auto hook = entry_hook(nullptr, [](void* original)
{
// ...
});
Fails to compile - unable to convert closure to function pointer
Removing the parameter pack from the wrapping lambda (by changing the following lines):
auto* function_ptr = +[](auto&&... args) to auto* function_ptr = +[]()
return bound(std::forward<decltype(args)>(args)...); to return bound();
Succesfully compiles and runs, although I would have assumed that by using a parameter pack that can be inferred at compile time on a lambda, wouldn't result in that lambda becoming a closure as such (being unconvertable to a function pointer as it requires a context)
I'm ideally trying to achieve:
const auto hook = entry_hook(nullptr, [](auto original, int param1, double param2)
{
// ...
});
Where original is of type void(*)(int, double) and entry_hook can expose a function pointer to the passed in lambda
Reference:
This answer converts a capturing lambda into a function pointer C++ lambda with captures as a function pointer
This answer converts a lambda into a function pointer Obtaining function pointer to lambda?
No: it's impossible.
Because the lambda that you trying to convert to a function pointer
[](auto && ... args) { /* something */ }
is a generic (and variadic; but the point is that is a generic one) lambda.
So is almost as a (variadic) template function (more exactly: as a struct with a variadic template operator() in it) as
template <typename ... As>
SomeRetType func (As && ... as)
{ /* do something */ }
and you can't have a pointer from func()
auto fp = &func; // same problem
because func() isn't an object but a set of objects.

Continue with the continuation monad tuple. Whats wrong?

Following with the tuple continuation monad, say I define a functor std_tuple to go from the cathegory of the monad-tuple to std::tuple:
auto std_tuple = [](auto... args)
{
return [=](auto f){ return f(std::make_tuple(args...)); };
};
Now we can use monad-tuples in contexts expecting std::tuple:
template<typename... ARGS>
void f( const std::tuple<ARGS...>& t ){}
int main()
{
tuple(1,2,3)(std_tuple)(f);
}
So far so good. Except this doesn't compile. Clang 3.4.1 complains:
note: candidate template ignored: couldn't infer template argument '$auto-1-0'
on the f(t) call inside the std_tuple functor.
Is this correct, are not those template argumments deducible? In case afirmative, why?
A simple case that reproduces your problem:
void f(int) {}
void f(double) {}
template<class T> void call_with_3( T t ) { t(3); }
int main() {
call_with_3( f );
}
Here we can see that which f to call cannot be determined at the point where we pass it to call_with_3. Now, you seemingly don't have multiple overloads (you only have one f!), but...
A template is not an instance. A template function is a factory of functions, not a function.
There is no object or value there to pass around.
When you pass a function name as an argument, overload resolution kicks in. If the target type is known (as a function reference or pointer) it is used to do overload resolution on the function name.
In this case, you are passing a function name to a template (auto argument), so there is no overload resolution that can be done, so no particular value can be found, so you get an error.
You can create an object whose effect is to do overload resolution on the invoked arguments with a given function name. I call them overload set objects.
static struct f_overload_set_t {
template<class... Args>
auto operator()(Args&&... args) const {
return f(std::forward<Args>(args)...);
}
} f_overload_set;
in C++11 you need a ->decltype( f( std::declval<Args>()... ) ) after the const.
Now f_overload_set(blah) will, when invoked will (almost) do what happens when you f(blah), but f_overload_set is an actual object. So you can pass it around.
Macros that generate such overload sets are relatively easy to write. They can also use lambdas, as the above is a lot like a stateless lambda if you think about it.
The nice thing about the stateless lambda based macro overload set generator is that it can be created at point-of-use. From #dyp's comment above:
#define OVERLOAD_SET( FUNC )\
([](auto&&... args){\
return FUNC(std::forward<decltype(args)>(args)...);\
})
(note: no brackets around FUNC, as that blocks ADL). Brackets around everything else, because otherwise if used within a subscript operation (operator[]), it would be parsed as a [[ starting an attribute, among other spots (thanks to #ecatmur))
which makes your code:
template<typename... ARGS>
void f( const std::tuple<ARGS...>& t ){}
int main() {
tuple(1,2,3)(std_tuple)(OVERLOAD_SET(f));
}