Generic std::function to store a generic lambda [duplicate] - c++

This question already has answers here:
C++14: Generic lambda with generic std::function as class member
(3 answers)
Closed 4 years ago.
When generic lambda is stored as a std::function, we need to provide a concrete type, something like,
std::function<double(double)>
thus binding to a specific type,
The following declaration:
std::function<auto(auto)>
throws a compiler error.
I understand that, from c++14 onwards, auto can be used to store return value of a lambda, but is there a way to achieve this when storing a lambda in std::function?

You can't. Not even with a custom wrote std::function. This is a fundamental limit of type erasure.
Intuitively, templates requires the type information available at the point of function call but type erasure in std::function destroys that information.
On a more detailed level, type erasure works by storing the set of operations in a type-agnostic way at compile-time, either implicitly by virtual functions or explicitly by function pointers. Templates are effectively an infinite family of operations and is thus impossible to be stored.
If you know the fixed set of function signatures you will be using, you can write a custom std::function.

You can't.
Generic lambda and std::function are completely different things.
You can rougly see an auto(auto) lambda as a not-template class with a template operator().
Something as
struct myUnnamedLambdaStruct
{
// ...
template <typename T>
auto operator() (T t) const
{ /* .... */ };
};
Where std::function() is the contrary: it's a (specialization of a) template class with a not-template operator()
template <typename>
class function;
template <typename RetType, typename ... ArgTypes>
class function<RetType(ArgTypes...)>
{
// a lot of other members/methods
public:
RetType operator() (ArgTypes ... args) const
{ /* .... */ }
};
So a generic lambda object doesn't contain a single operator() but a set of operator() where a std::function object contain a single operator().
You can "save" a generic lambda in a std::function but only fixing, one time for all, the RetType and the ArgTypes.... That is: selecting a single operator(), in the available set of operator()s, and forgetting all the others.

Related

Decomposing C++17 function-like object in generic fashion?

In C++17 suppose I have a function-like object passed as a parameter to some template:
template<typename F>
void g(F f) {
auto x = f(/*...*/);
}
There are lots of different types F could be, such as a function pointer, a std::function, a lambda expression, and in fact any class type that implements operator().
Is there any way to get the function-like objects arity and type of its parameters and the type of its return type?
I mean, ultimately F could be a class that overloads operator() with multiple different member functions, each with different arities, parameter types and return types - so there isn't a fully-general answer (unless there is some way to iterate that overload set, which I don't think there is).
But for the typical case where a function call expression involving f results in a single overload, is there a solution?
(also if there is any progress in C++20, worth mentioning too)
C++17's adds deduction guides for std::function, which we can use to do the deduce the function signature of non-overloaded function-like objects:
template <typename R, typename... Args>
constexpr auto do_something_with_the_signature(std::function<R(Args...)>) {
// Assuming that you only care about the return type.
// Otherwise, you may want some kind of wrapper to extract the signature to
// avoid runtime cost
}
...
using some_type_computation =
decltype(do_something_with_the_signature(std::function(f)));
If you only wanted the return type, you could just use:
using result_type = typename decltype(std::function(f))::result_type;
If you want to avoid std::function altogether because of the compile-time costs, you can implement your own version of the deduction guides for your own type (possibly as general as a function_traits type trait). A sketch of how you might implement the deduction guides yourself can be seen in my answer here: https://stackoverflow.com/a/66038056/1896169

Extract type from subexpression in template

Given the following templated function:
template <typename T>
void f(std::function <void (T)>) {}
Can I extract T without having to explicitly mention it when calling f?
f<int>([](int){}); works fine but I'd like T to be deduced and f([](int){}); to just work. The latter errors out with "no matching function for call to".
You can deduce T if the object passed into the function actually has type std::function<void(T)>. If the type you pass in is a lambda, then you'll have to deduce it from the type of the lambda's function call operator, like so:
template <class Callable, class Arg, class T>
void f_helper(Callable callable, Ret (Callable::*)(T)) {
// do something with T
}
template <class Callable>
void f(Callable callable) {
f_helper(callable, &callable::operator());
}
Actually, in reality it is a bit more annoying than this, because you need at least two overloads for f_helper, according to whether the lambda is declared mutable (which determines whether operator() is const), and in C++17 you also need to double the number of overloads again according to whether the lambda is noexcept.
The standard library sidesteps issues like this by not attempting to extract the argument type from the callables you pass to algorithms such as std::sort. It just accepts an arbitrary callable type and then tries to call it.

Template functors vs functions

I have been looking at some of the Boost source code and noticed they implement templated functions by using a functor instead of a plain function? Is there a reason for this?
For example:
template<typename Foo, typename Bar>
struct functor {
Bar operator()(const Foo& foo) {
return foo.as_bar();
}
};
as opposed to:
template<typename Foo, typename Bar>
Bar func(const Foo& foo) {
return foo.as_bar();
}
The only advantage I can come up with is it allows classes to inherit the function?
There are two main reasons: The first is, as pythonic metaphor noted, partial specialization is only valid for classes and not functions. Note that functions can use overloads to overcome this problem generally, but often if you are doing metaprogramming it's easier and more generic to use partial specialization. I'd actually think this was the main reason.
The second reason is that anytime that code wants to accept a function object (like in the STL, e.g. std::transform), it will have a type template parameter. If you pass a functor or a lambda, the exact type is known at compile time, and you don't pay for indirection, and inlining can be performed. If you pass a function pointer (or a std::function), only the signature is known at compile time, and you pay for an indirection (and you can't inline). For instance, std::sort can be considerably faster with a functor than a function pointer.
Note that there is a little used feature called function pointer template parameters; these are non type template parameters that specialize on a specific function, and thus can remove indirection. However, if you use one of these, you can't use a functor at all. So most code that wants to accepts a function object does it the way I described above.

Generic lambdas Vs Standard template functions (What to use and When)

Generic Lambdas are a way of defining lambdas that read as follows:
auto identity = [](auto a){return a;}
Compare this with:
template <typename T>
T Identity(T t){return t;}
or with
template <typename T>
struct Identity { T operator()(T a) { return a; } };
This is my understanding
lambdas allow context capture using [&], [=], etc, I am not sure how this will be used / applied in generic lambdas. Is this the main difference ?
generic lambdas can be cast to function pointers whereas, template specialisation can be cast to function pointers.
A simple real world example will be useful to understand what to use and when.
[Appended] Here is the generic lambda proposal : http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3559.pdf
Pretty much like lambdas, generic lambdas are defined through equivalence to an implicitly defined function object (where non-generic lambdas have the additional ability that with empty capture they can convert to a function pointer). The only real difference between generic and non-generic lambdas is that generic lambda have call operator which is a function template while it is a non-template for non-generic lambdas.
For generic lambdas the conversion to function pointers doesn't exist (see 5.1.2 [expr.prim.lambda] paragraph 6).
Since generic lambdas are still objects with a call operator, they can be used directly as an argument where a generic function objects can be used. That is not the case for a function templates: these behave more like an overload set and you need to get the instantiated before you can pass them as a function object.
Although you can't get a pointer to a function template, you can get a pointer to a function template specialization (as #Columbo pointed out in a comment, a function template specialization is a function). You can't get a pointer to a function out of a generic lambda.
Function templates participate in overload resolution while function objects don't really participate: when an object is found during name look-up this object is chosen even if there could be functions found with the same name and with a nice match for overloading. This implies, that these two are not equivalent:
template <typename T>
auto identity(T value) { return value; }
auto identity = [](auto value) { return value; }
The second implementation hijacks the name while the former is used as a candidate in overload resolution.
Aside from auxiliary objects created from within a function I would use generic lambdas for functions which are not meant as customization points (e.g. it would be nice if standard library algorithms were such objects). The main benefit is that function objects can be readily adapted, e.g., using std::bind() which is not true for function templates.

Getting Return Type of Callable Type in VS2010

I have a template class with a callable type-parameter <typename Callable>.
I know that Callable indeed creates a callable object, and is often a lambda.
In my particular case, I also know the number (arity) and type of arguments (just one).
How can I get the return type of this callable type Callable on VS2010?
See std::result_of.
Pretending the object is invoked with one int argument, you could do things like:
using return_type = typename std::result_of<Callable(int)>::type;
This isn't generally possible.
There are multiple ways to have callable types, including lambdas and structs that overload operator().
C++ does not have nearly the type of reflection that languages like C# do, and it is impossible to do with the tools that C++ offers.
If all you want is to store the result of that "callable" into a variable, then you can just use auto.
If you actually want to do stuff with the result based on its type, then this question might help.
Basically, add this to your code.
template <typename T, typename U>
struct same_type
{
static const bool value = false;
};
template <typename T>
struct same_type< T, T >
{
static const bool value = true;
};
Then, if you have auto result = func(param);, where func is of type Callable, you can check the type of result with the following:
if (same_type<decltype(result), int>().value)
{
// code, knowing that result is of type int
}
else if (same_type<decltype(result), const char*>().value)
{
// code, knowing that result is of type const char*
}
// else if ... etc.
I tried various approaches, but support for C++11 in VS2010 is only partial and most approaches simply didn't compile.
What did finally work (on VS2010) is the following:
// When arity is known
typedef decltype(callbackInstance0()) return_type0;
typedef decltype(callbackInstance1(argInstance)) return_type1;
Where callbackInstanceX is the actual callable object to be used and argInstance is the actual arg to be passed to callbackInstance.
Note that this is not a general solution (though sufficient in my case) because:
It cannot be used outside of a function where you don't have actual instances of these types, but only the types, as in the class definition;
The callable arity must be known.