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

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

Related

How to pass std::sqrt as an argument

Im trying to create a generic function Foo that will accept an argument and Op what will be applied to it.
template <template<class> class Op>
float foo(float boo) {
return Op(boo);
}
template <template<class> class Op>
float foo(float a, float b) {
return Op(a, b);
}
void caller() {
float boo = 2.3;
auto res1 = foo<std::plus>(boo, boo); // works
auto res2 = foo<std::sqrt>(boo); // fail. error: no instance of overloaded function.
auto res3 = foo<std::exp>(boo); // fail. error: no instance of overloaded function
}
I think its related that std::sqrt is
"A set of overloads or a function template accepting an argument of
any integral type. "
while std::plus is
Function object for performing addition.
Can someone, please, help fix this? How do i pass std::sqrt and std::exp to foo?
As you've identified, the problem is that your template expects a type (because that's how you've written it), and though std::plus is a type (a functor), std::sqrt is a function.
It's hard to give a concrete solution for your problem, because you never showed your usage of Op.
But, generally, this is easy to do with an auto template parameter:
template <auto Op>
float foo(const float boo) {
return Op(boo);
}
If your version of C++ is too old, you'll need to add a version that takes a function pointer instead.
std::sqrt is an overloaded function, not a type. A simple fix would be to write a generic lambda that wraps std::sqrt, and then use its type when calling foo, like this:
auto sqrt = [](auto n) { return std::sqrt(n); };
auto res2 = foo<decltype(sqrt)>(boo); // ok
And you can do the same for std::exp.
Whether this is a good fix depends on how you want to use the Op parameter, which is not clear from the question.
You can't pass an overload set as a template argument. A simple workaround could be to wrap sqrt and exp into functors with a templated operator():
struct Sqrt {
template<class T>
T operator()(T t) const { return std::sqrt(t); }
};
struct Exp {
template<class T>
T operator()(T t) const { return std::exp(t); }
};
Then the following will work
auto res2 = foo<Sqrt>(boo);
auto res3 = foo<Exp>(boo);

Simplest way to determine return type of function

Given a very simple, but lengthy function, such as:
int foo(int a, int b, int c, int d) {
return 1;
}
// using ReturnTypeOfFoo = ???
What is the most simple and concise way to determine the function's return type (ReturnTypeOfFoo, in this example: int) at compile time without repeating the function's parameter types (by name only, since it is known that the function does not have any additional overloads)?
You can leverage std::function here which will give you an alias for the functions return type. This does require C++17 support, since it relies on class template argument deduction, but it will work with any callable type:
using ReturnTypeOfFoo = decltype(std::function{foo})::result_type;
We can make this a little more generic like
template<typename Callable>
using return_type_of_t =
typename decltype(std::function{std::declval<Callable>()})::result_type;
which then lets you use it like
int foo(int a, int b, int c, int d) {
return 1;
}
auto bar = [](){ return 1; };
struct baz_
{
double operator()(){ return 0; }
} baz;
using ReturnTypeOfFoo = return_type_of_t<decltype(foo)>;
using ReturnTypeOfBar = return_type_of_t<decltype(bar)>;
using ReturnTypeOfBaz = return_type_of_t<decltype(baz)>;
Most simple and concise is probably:
template <typename R, typename... Args>
R return_type_of(R(*)(Args...));
using ReturnTypeOfFoo = decltype(return_type_of(foo));
Note that this won't work for function objects or pointers to member functions. Just functions, that aren't overloaded or templates, or noexcept.
But this can be extended to support all of those cases, if so desired, by adding more overloads of return_type_of.
I don't know if is the simplest way (if you can use C++17 surely isn't: see NathanOliver's answer) but... what about declaring a function as follows:
template <typename R, typename ... Args>
R getRetType (R(*)(Args...));
and using decltype()?
using ReturnTypeOfFoo = decltype( getRetType(&foo) );
Observe that getRetType() is only declared and not defined because is called only a decltype(), so only the returned type is relevant.

Getting return type of an overloaded member function

I am trying to determine the return type of an overloaded member function to later use that type in my function template (see the example below). Cannot figure out how to do it using C++11 templating machinery (without modifying the definitions for struct A and B in the code below). Is this doable (in C++11 in general and MSVS2013 in particular) and how?
struct A{};
struct B{};
struct X
{
double f(A&);
int* f(B&);
};
template<typename T, typename R = /*??? what X::f(T) returns ???*/>
R ff(T& arg)
{
X x;
R r = x.f(arg); // preferably if I can create local variables of type R here
return r;
}
int main()
{
A a; ff(a);
B b; ff(b);
}
You can use decltype() for this, using std::declval to simulate values of the types needed to create the method call expression:
typename R = decltype(std::declval<X>().f(std::declval<T&>()))
Here is a demo that outputs the type ID of R; you can see that it correctly deduces double and int * for ff(a) and ff(b) respectively.
Side note: the entire body of your template function can be reduced to return X().f(arg);.
You can also use C++14 auto return type deduction like this:
template<typename T>
auto ff(T& arg)
{
X x;
auto r = x.f(arg);
return r;
}
In C++11, you can use the late return type:
template <typename T>
auto ff(T&& arg) -> decltype(std::declval<X>().f(arg))
{
return X().f(arg);
}
In C++14, you can even omit the late return type and let the compiler determine everything itself, like in Baum mit Augen's answer.
Edit: made the late return type work for non-default constructable types X.

How to make a SFINAE-based Y combinator in C++?

I was thinking about the implicit templates of C++14, and I'm trying to declare a function to match an specific argument type (SFINAE and traits still give me headaches). I'm not sure how to explain what I want, but I'm trying to make a Y combinator (just to see if it's possible, not intended for production).
I'm trying to declare a function:
template<typename T>
my_traits<T>::return_type Y(T t) {
// ...
};
Such that T is a function (or a functor) that matches
std::function<R(F, Args...)>
// where F (and above return_type) will be
std::function<R(Args...)>
Which would take any number of arguments, but the first should be a function with the same return type and the same arguments (except this function itself). The first parameter to the operator () of the functor is a template.
The usage I want to achieve:
auto fib = [](auto myself, int x) {
if(x < 2)
return 1;
return myself(x - 1) + myself(x - 2);
};
// The returned type of fib should be assignable to std::function<int(int)>
I wasn't able to take the return type of the T type (because of the overloaded operator ()). What I'm trying to make is possible? How could I make it?
Edit:
Seeing it from a different angle, I'm trying to make this work:
struct my_functor {
template<typename T>
char operator () (T t, int x, float y) { /* ... */ };
};
template<typename T>
struct my_traits {
typedef /* ... */ result_type;
/* ... */
};
// I want this to be std::function<char(int, float)>, based on my_functor
using my_result =
my_traits<my_functor>::result_type;
It is not possible in C++14 return type deduction to deduce int(int) out of int(T, int) as OP desires.
However, we can mask the first parameter of the result using the following approach. The struct YCombinator is instantiated with a non-recursive function object member, whose first argument is a version of itself without the first argument. YCombinator provides a call operator that receives the arguments of the non-recursive function and then returns its function object member after substituting itself for the first argument. This technique allows the programmer to avoid the messiness of myself(myself, ...) calls within the definition of the recursive function.
template<typename Functor>
struct YCombinator
{
Functor functor;
template<typename... Args>
decltype(auto) operator()(Args&&... args)
{
return functor(*this, std::forward<Args>(args)...);
}
};
A make_YCombinator utility template allows for a streamlined usage pattern. This compiles run runs in GCC 4.9.0.
template<typename Functor>
decltype(auto) make_YCombinator(Functor f) { return YCombinator<Functor> { f }; }
int main()
{
auto fib = make_YCombinator([](auto self, int n) -> int { return n < 2 ? 1 : self(n - 1) + self(n - 2); });
for (int i = 0; i < 10 ; ++i)
cout << "fib(" << i << ") = " << fib(i) << endl;
return 0;
}
Since the non-recursive function is not defined at time that the recursive function is defined, in general the recursive function must have an explicit return type.
Edit:
However, it may be possible for the compiler to deduce the return type in certain cases if the programmer takes care to indicate the return type of the recursive function before use of the non-recursive function. While the above construction requires an explicit return type, in the following GCC 4.9.0 has no problem deducing the return type:
auto fib = make_YCombinator([](auto self, int n) { if (n < 2) return 1; return self(n - 1) + self(n - 2); });
To pin this down just a bit further, here is a quote from the draft C++14 standard on return type deduction [7.1.6.4.11]:
If the type of an entity with an undeduced placeholder type is needed
to determine the type of an expression, the program is ill-formed.
Once a return statement has been seen in a function, however, the
return type deduced from that statement can be used in the rest of the
function, including in other return statements. [ Example:
auto n = n; // error, n’s type is unknown
auto f();
void g() { &f; } // error, f’s return type is unknown
auto sum(int i) {
if (i == 1)
return i; // sum’s return type is int
else
return sum(i-1)+i; // OK, sum’s return type has been deduced
}
—end example ]
It's a really hacky approach, and has severe limitations, but here it goes:
First, we need a class that pretends to support every possible operation (as far as possible), such as the fake_anything class. Note that this isn't perfect since at a minimum . and :: won't work. To fake a functor, we give it a function call operator:
template<class... Ts> fake_anything operator()(Ts&&...) const;
Knowing that the lambda has only one operator(), and that operator() has only one template parameter allows us to extract its signature with decltype(&T::operator()<fake_anything>).
For this to work, the lambda's return type must be explicitly specified; it can't use deduction, since otherwise the deduced return types will probably conflict.
Finally we can obtain the other arguments to the lambda and the return type using the standard partial specialization approach:
template<class T>
struct extract_signature;
template<class T, class R, class FA, class...Args>
struct extract_signature<R (T::*)(FA, Args...)> {
static_assert(std::is_same<fake_anything, std::decay_t<FA>>::value, "Unexpected signature");
using type = std::function<R(Args...)>;
};
template<class T, class R, class FA, class...Args>
struct extract_signature<R (T::*)(FA, Args...) const> {
static_assert(std::is_same<fake_anything, std::decay_t<FA>>::value, "Unexpected signature");
using type = std::function<R(Args...)>;
};
// other cv- and ref-qualifier versions omitted - not relevant to lambdas
// we can also static_assert that none of Args is fake_anything, or reference to it, etc.
And add an alias template to hide all the ugliness of the hack:
template<class T>
using signature_t = typename extract_signature<decltype(&T::template operator()<fake_anything>)>::type;
And finally we can check that
static_assert(std::is_same<signature_t<decltype(fib)>,
std::function<int(int)>>::value, "Oops");
Demo.
The limitations:
The return type of operator() must be explicitly specified. You cannot use automatic return type deduction, unless all of the return statements return the same type regardless of the return type of the functor.
The faking is very imperfect.
This works for operator() of a particular form only: template<class T> R operator()(T, argument-types...) with or without const, where the first parameter is T or a reference to possibly cv-qualified T.

Function wrapper that works for all kinds of functors without casting

I'd like to create a function that takes a weak pointer and any kind of functor (lambda, std::function, whatever) and returns a new functor that only executes the original functor when the pointer was not removed in the meantime (so let's assume there is a WeakPointer type with such semantics). This should all work for any functor without having to specify explicitly the functor signature through template parameters or a cast.
EDIT:
Some commenters have pointed out that std::function - which I used in my approach - might not be needed at all and neither might the lambda (though in my original question I also forgot to mention that I need to capture the weak pointer parameter), so any alternative solution that solves the general problem is of course is also highly appreciated, maybe I didn't think enough outside the box and was to focused on using a lambda + std::function. In any case, here goes what I tried so far:
template<typename... ArgumentTypes>
inline std::function<void(ArgumentTypes...)> wrap(WeakPointer pWeakPointer, const std::function<void(ArgumentTypes...)>&& fun)
{
return [=] (ArgumentTypes... args)
{
if(pWeakPointer)
{
fun(args...);
}
};
}
This works well without having to explicitly specify the argument types if I pass an std::function, but fails if I pass a lambda expression. I guess this because the std::function constructor ambiguity as asked in this question. In any case, I tried the following helper to be able to capture any kind of function:
template<typename F, typename... ArgumentTypes>
inline function<void(ArgumentTypes...)> wrap(WeakPointer pWeakPointer, const F&& fun)
{
return wrap(pWeakPointer, std::function<void(ArgumentTypes...)>(fun));
}
This now works for lambdas that don't have parameters but fails for other ones, since it always instantiates ArgumentTypes... with an empty set.
I can think of two solution to the problem, but didn't manage to implement either of them:
Make sure that the correct std::function (or another Functor helper type) is created for a lambda, i.e. that a lambda with signature R(T1) results in a std::function(R(T1)) so that the ArgumentTypes... will be correctly deduced
Do not put the ArgumentTypes... as a template parameter instead have some other way (boost?) to get the argument pack from the lambda/functor, so I could do something like this:
-
template<typename F>
inline auto wrap(WeakPointer pWeakPointer, const F&& fun) -> std::function<void(arg_pack_from_functor(fun))>
{
return wrap(pWeakPointer, std::function<void(arg_pack_from_functor(fun))(fun));
}
You don't have to use a lambda.
#include <iostream>
#include <type_traits>
template <typename F>
struct Wrapper {
F f;
template <typename... T>
auto operator()(T&&... args) -> typename std::result_of<F(T...)>::type {
std::cout << "calling f with " << sizeof...(args) << " arguments.\n";
return f(std::forward<T>(args)...);
}
};
template <typename F>
Wrapper<F> wrap(F&& f) {
return {std::forward<F>(f)};
}
int main() {
auto f = wrap([](int x, int y) { return x + y; });
std::cout << f(2, 3) << std::endl;
return 0;
}
Assuming the weak pointer takes the place of the first argument, here's how I would do it with a generic lambda (with move captures) and if C++ would allow me to return such a lambda:
template<typename Functor, typename Arg, typename... Args>
auto wrap(Functor&& functor, Arg&& arg)
{
return [functor = std::forward<Functor>(functor)
, arg = std::forward<Arg>(arg)]<typename... Rest>(Rest&&... rest)
{
if(auto e = arg.lock()) {
return functor(*e, std::forward<Rest>(rest)...);
} else {
// Let's handwave this for the time being
}
};
}
It is possible to translate this hypothetical code into actual C++11 code if we manually 'unroll' the generic lambda into a polymorphic functor:
template<typename F, typename Pointer>
struct wrap_type {
F f;
Pointer pointer;
template<typename... Rest>
auto operator()(Rest&&... rest)
-> decltype( f(*pointer.lock(), std::forward<Rest>(rest)...) )
{
if(auto p = lock()) {
return f(*p, std::forward<Rest>(rest)...);
} else {
// Handle
}
}
};
template<typename F, typename Pointer>
wrap_type<typename std::decay<F>::type, typename std::decay<Pointer>::type>
wrap(F&& f, Pointer&& pointer)
{ return { std::forward<F>(f), std::forward<Pointer>(pointer) }; }
There are two straightforward options for handling the case where the pointer has expired: either propagate an exception, or return an out-of-band value. In the latter case the return type would become e.g. optional<decltype( f(*pointer.lock(), std::forward<Rest>(rest)...) )> and // Handle would become return {};.
Example code to see everything in action.
[ Exercise for the ambitious: improve the code so that it's possible to use auto g = wrap(f, w, 4); auto r = g();. Then, if it's not already the case, improve it further so that auto g = wrap(f, w1, 4, w5); is also possible and 'does the right thing'. ]