Variadic template function accepting lambda - c++

I'm trying to understand the compiler error that I'm getting fo the code below. I've got a variadic template function which accepts a lambda
with the specified types, and attempting to call that function results in the template not being considered a valid candidate due to a mismatch.
#include <functional>
template<typename ... ResultTypes>
void executeWithResultHandler(std::function<void (ResultTypes...)> lambda)
{
}
int main(int argc, char **argv)
{
executeWithResultHandler<int>([] (int arg) {
});
return 0;
}
This results in the following error:
$ c++ -std=c++11 reduction.cpp
reduction.cpp:10:5: error: no matching function for call to 'executeWithResultHandler'
executeWithResultHandler<int>([] (int arg) {
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~
reduction.cpp:4:6: note: candidate template ignored: could not match 'function<void (int, type-parameter-0-0...)>' against
'<lambda at reduction.cpp:10:35>'
void executeWithResultHandler(std::function<void (ResultTypes...)> lambda)
^
1 error generated.
If I change the declaration to not be variadic:
template<typename ResultType>
void executeWithResultHandler(std::function<void (ResultType)> lambda)
{
}
then it works for the toy example above, but for the real problem I need arbitrary arguments.
Is there something I’m missing here, or anther way to accomplish this?
EDIT: This was marked as a duplicate incorrectly, I believe- the dupe does not answer the question I'm asking. This question specifically has to do with the variadic template issue here: Please note that, when I switch the template to be non-variadic the lambda converts to the std::function type correctly, as expected. This is true regardless of the number of arguments, as long as that is not handled in a variadic fashion.
However, it does not work with the variadic version specifically, despite an expectation that the parameter pack is unpacked to a set of real parameters, and the explicit specification of the template parameter list at the function call site.

The problem with variadic templates in your case is that the compiler does not know whether the int you explicitly specified is the complete list for ResultTypes... or not, so it tries to deduce the optional remaining arguments from the parameter you gave it, and that obviously fails. This is a common pitfall with variadic template arguments and it is not limited to lambdas.
A solution always implies that you take away this option from the compiler, e.g.
template<typename ... ResultTypes>
void executeWithResultHandler_impl(std::function<void (ResultTypes...)> lambda)
{
}
template<typename ... ResultTypes, typename F>
void executeWithResultHandler(F&& lambda)
{
executeWithResultHandler_impl(std::function<void (ResultTypes...)>(lambda));
}

The question I'd previously linked as duplicate explains exactly what is going in your case.
An std::function is not a lambda, it is type of container that can store any kind of callable object. You can assign a lambda to an std::function, but in that case the necessary conversion is performed by the std::function constructor.
In your example
template<typename ... ResultTypes>
void executeWithResultHandler(std::function<void (ResultTypes...)> lambda)
{}
executeWithResultHandler<int>([](int arg){});
the compiler has no way of inferring the types in the parameter pack ResultTypes from the lambda expression above. Template argument deduction requires exact matches, implicit conversions are not considered, and the types involved here, as mentioned earlier, are completely different.
If I change the declaration to not be variadic then it works
template<typename ResultType>
void executeWithResultHandler(std::function<void (ResultType)> lambda)
{}
executeWithResultHandler<int>([](int arg){});
This works because there's no template argument deduction involved anymore. executeWithResultHandler takes exactly one template parameter, which you've explicitly specified, and because a lambda is implicitly convertible to std::function, overload resolution will find a match.
Note that in the first case there may have been more template arguments, in addition to int, that you hadn't specified explicitly.
You can get your original example to work by explicitly converting the lambda to std::function.
executeWithResultHandler<int>(std::function<void(int)>([] (int arg) {}));

Related

Distinguish between function references/pointers accepting const and non-const argument with same name as function parameter

Let's consider two functions with same names:
int func(int&)
{
return 7;
}
int func(const int&)
{
return 5;
}
Let int mutableValue = 5 be defined somewhere. Is there any possibility that template function call in call(mutableValue, func) would take only int func(int&)?
I don't want to use static_cast<int(&)(int&)> - because it's so noisy.
Naive implementation:
template<typename Arg, typename Ret>
void call(Arg& val, Ret (&fun)(Arg&))
{
fun(val);
}
works on gcc, but does not work on clang - solutions must work on both compilers.
Accepting only const Arg& is easy. Deleting const Arg& overload does not help.
I believe clang is the only compiler that gets this right. This should not compile. As long as the argument to fun is an overload set that does not contain any function templates, template argument deduction will be attempted for each member of the overload set. If template argument deduction would succeed for more than one of these overloads, the function parameter becomes a non-deduced context [temp.deduct.call]/6.2.
In the example in question, the argument to fun is the overload set func, which does indeed not contain any function templates. Thus, argument deduction on fun is attempted for both overloads of func, which succeeds. As a result, the parameter fun becomes a non-deduced context, which means that no argument can be deduced for Ret and the call fails as there are no candidates (exactly what clang complains about).
To disambiguate this call, simply explicitly specify the argument for the first template parameter:
call<int>(mutableValue, func)
Since it seems to be impossible to resolve the ambiguity in one template argument deduction:
If you are ok with a change of the syntax at the call site you can separate the call into two calls/deduction passes:
template<typename Arg>
auto call(Arg& val)
{
return [&](auto (&fun)(Arg&)){ fun(val); };
}
to be called as
call(mutableValue)(func)
Another downside is however that the lambda could be stored by a caller and accidentally used later when the captured reference isn't valid anymore.
You could maybe hide this in a macro call, so that the syntax matches what you want and to reduce the potential for misuse.

Constructing std::function argument from lambda

I have the following templated function (C++ latest standard is enabled in the compiler - but maybe 17 would be enough).
#include <functional>
template<typename TReturn, typename ...TArgs>
void MyFunction(const std::function<TReturn(TArgs...)>& callback);
int main()
{
MyFunction(std::function([](int){}));
MyFunction([](int){});
}
The first call compiles, when I explicitly convert it to std::function, but the second case does not.
In the first case the template deduction is done automatically, the compiler only knows that it shall convert it to some std::function and able to deduce the parameter and return type.
However in the second case it shall(?) also know that the lambda shall be converted to some std::function, but still unable to do it.
Is there a solution to get the second one running? Or can it be that for templates the automatic conversion does not take place at all?
The error message is:
error C2672: 'MyFunction': no matching overloaded function found
error C2784: 'void MyFunction(const std::function<_Ret(_Types...)> &)': could not deduce template argument for 'const std::function<_Ret(_Types...)>
note: see declaration of 'MyFunction'
What I am aiming for is a "python style decorator". So basically this:
template<typename TReturn, typename ...TArgs>
auto MyFunction(std::function<TReturn(TArgs...)>&& callback) -> std::function<TReturn(TArgs...)>
{
return [callback = std::move(callback)](TArgs... args)->TReturn
{
return callback(std::forward<TArgs>(args)...);
};
}
If I used a template instead of std::function, the how would I deduce the parameter pack and return value? Is there some way to get it from a callable via some "callable traits"?
Or can it be that for templates the automatic conversion does not take place at all?
Yes. Implicit conversions won't be considered in template argument deduction.
Type deduction does not consider implicit conversions (other than type adjustments listed above): that's the job for overload resolution, which happens later.
That means given MyFunction([](int){});, the implicit conversion (from lambda to std::function) won't be considered, then the deduction for TReturn and TArgs fails and the invocation attempt fails too.
As the workarounds, you can
Use explicit conversion as you showed
As the comment suggested, just use a single template parameter for functors. e.g.
template<typename F>
auto MyFunction2(F&& callback)
{
return [callback = std::move(callback)](auto&&... args)
{
return callback(std::forward<decltype(args)>(args)...);
};
}

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.

Why can't my C++ compiler deduce template argument for boost function?

I define a method like so:
template <class ArgT>
void foo(ArgT arg, ::boost::function< void(ArgT) > func)
{
func(arg);
}
and use it like this --for instance--:
foo(2, [](int i) -> void { cout << i << endl; });
Why can't the compiler deduce the type since it's definitely an int?
I get 'void foo(ArgT,boost::function<void(ArgT)>)' : could not deduce template argument for 'boost::function<void(ArgT)>' from 'anonymous-namespace'::<lambda0>'.
While C++ lambdas are strictly monomorphic, they are merely shorthand for function objects (aka functors), and in general functors can be polymorphic; i.e., their call operators can be overloaded or templated. As a result, functors (and, consequently, lambdas) are never implicitly convertible to templated std::function<> (or boost::function<>) instances because functors' operator() argument types are not automatically inferable.
To phrase it slightly differently, the natural type of your lambda expression is a functor with a parameterless constructor and an operator() with the signature void operator ()(int) const. However obvious this fact may be to you and I, it's not automatically inferrable that ArgT should resolve to int because lambdas are functors and functors' operator()s are possible to overload and template.
TL;DR: What you want isn't possible.
You want a conversion from the lambda function to boost::function<void(ArgT)> where ArgT is to be deduced. As a general rule, you cannot have type deduction and conversion in the same argument of a function: no conversions take place when deducing a template parameter.
The reasoning behind this is as follows. There are three types involved here: (1) the template parameter, (2) the function parameter type, (3) the passed object type. Two of the types (1 and 2) can be deduced from one another, but both are unknown. If the compiler can assume 2 and 3 are the same type, the problem is solved, but if all the compiler knows is that 3 can be converted to 2 there could be any number of possible solutions, and the compiler is not expected to solve the problem. In practice we know that in this particular case there is only one possible solution, but the standard does not make a distinction between cases.
The rule above applies in all deducible contexts, even if the template parameter can be deduced from another function parameter. The solution here is make the relevant function parameter a non-deducible context, ie a context in which the compiler will never attempt to deduce the template parameter from the function parameter. This can be done as follows:
template <class T> struct identity { typename T type; };
template <class ArgT>
void foo(ArgT arg, typename identity<::boost::function<void(ArgT)>>::type func)
{
func(arg);
}

Template argument deduction from function body

If we've this function template,
template<typename T>
void f(T param) {}
Then we can call it in the following ways,
int i=0;
f<int>(i);//T=int : no need to deduce T
f(i); //T=int : deduced T from the function argument!
//likewise
sample s;
f(s); //T=sample : deduced T from the function argument!
Now consider this variant of the above function template,
template<typename TArg, typename TBody>
void g(TArg param)
{
TBody v=param.member;
}
Now, can the compiler deduce the template arguments if we write,
sample s;
g(s); //TArg=sample, TBody=int??
Suppose sample is defined as,
struct sample
{
int member;
};
There are basically two questions:
Can the compiler deduce the template arguments in the second example?
If no, then why? Is there any difficulty? If the Standard doesn't say anything about "template argument deduction from function body", then is it because the argument(s) cannot be deduced? Or it didn't consider such deduction so as to avoid adding more complexity to the language? Or what?
I would like know your views on such deduction.
EDIT:
By the way, the GCC is able to deduce function arguments if we write this code:
template<typename T>
void h(T p)
{
cout << "g() " << p << endl;
return;
}
template<typename T>
void g(T p)
{
h(p.member); //if here GCC can deduce T for h(), then why not TBody in the previous example?
return;
}
Working demonstration for this example : http://www.ideone.com/cvXEA
Not working demonstration for the previous example: http://www.ideone.com/UX038
You probably already concluded that the compiler won't deduce TBody by examining the type of sample.member. This would add yet another level of complexity to the template deduction algorithm.
The template matching algorithm only considers function signatures, not their bodies. While not used too often, it's perfectly legal to simply declare a templated function without providing the body:
template <typename T> void f(T param);
This satisfies the compiler. In order to satisfy the linker, you must of course also define the function body somewhere, and ensure that all required instantiations have been provided. But the function body does not necessarily have to be visible to client code of the template function, as long as the required instantiations are available at link time. The body would have to explicitly instantiate the function, eg:
template <> void f(int param);
But this only partially applies to your questions, because you could imagine a scenario like the following, where a 2nd parameter could be deduced from the a provided default parameter, and which won't compile:
template<typename TArg, typename TBody>
void g(TArg param, TBody body = param.member); // won't deduce TBody from TArg
The template matching algorithm considers only the actual type, not any potential nested member types in case of classes or structs. This would have added another level of complexity which apparently was judged to be too complex. Where should the algorithm stop? Are members of members, and so forth, also to be considered?
Also, it's not required because there are other means of achieving the same intention, as shown in the example below.
Nothing prevents you from writing:
struct sample
{
typedef int MemberType;
MemberType member;
};
template<typename TArg>
void g(TArg param)
{
typename TArg::MemberType v = param.member;
}
sample s = { 0 };
g(s);
in order to obtain the same effect.
Regarding your sample you added after editing: whereas it seems that h(p.member) does depend on the member of the struct, and hence the template matching algorithm should fail, it doesn't because you made it a two-step process:
Upon seeing g(s);, the compiler looks for any function taking an argument of type sample (templated or not!). In your case, the best match is void g(T p). At this point, the compiler has not even looked at the body of g(T p) yet!.
Now, the compiler creates a instance of g(T p), specialized for T: sample. So when it sees h(p.member) it knows that p.member is of type int, and will try locate a function h() taking an argument of type int. Your template function h(T p) turns out to be the best match.
Note that if you had written (note the NOT_A_member):
template<typename T>
void g(T p)
{
h(p.NOT_A_member);
return;
}
then the compiler would still consider g() a valid match at stage 1. You then get an error when it turns out that sample does not have a member called NOT_A_member.
There are a couple of things that the compiler cannot possibly do with the code that you provide, the first of which is deduce the second template argument TBody. First, type deduction is only applied to the arguments of the function when the compiler is trying to match the call. At that point the definition of the templated function is not even looked at.
For extra credits, even if the compiler were to look the function definition, the code TBody v = parameter.member is non-deducible in itself, as there are potentially infinite data types that can accept a parameter.member in the constructor.
Now, on the second block of code. To understand it the whole process of template compilation starts when the compiler sees the function call g(x) at that point of call. The compiler sees that the best candidate is the template function template <typename T> void g( T ) and determines what the type T is as part of the overload resolution. Once the compiler determines that it is a call to the template, it performs the first pass of compilation on that function.
During the first pass, syntactic checks are perform without an actual substitution of the type, so the template argument T is still any-type and the argument p is of a yet-unknown type. During the first pass, the code is verified, but dependent names are skipped and their meaning is just assumed. When the compiler sees p.member, and p is of type T that is a template argument it assumes that it will be a member of the yet unknown type (this is the reason why if it is a type you would have to qualify it here with typename). The call h(p.member); is also dependent on the type argument T and is left as it is, assuming that once the type substitution takes place everything will make sense.
Then the compiler does actually substitute the type. At this step T is no longer a generic type, but it represents the concrete type sample. Now the compiler during the second pass tries to fill in the gaps that were left during the first pass. When it sees p.member it looks member inside the type and determines that it is an int and tries to resolve the call h( p.member ); with that knowledge. Because the type T has been resolved before this second stage, this is equivalent to the outside call g(x): all types are known and the compiler only needs to resolve what is the best overload for a function call h that takes an argument of type int&, and the whole process starts again, the template h is found as the best candidate, and ...
It is really important for metaprogramming to understand that type deduction is performed only on the actual signature of the function and not the body, and that is what makes it non-trivial for beginners. Using enable_if (from boost or elsewhere) in the function signature as argument or return type is not a coincidence, but the only way of having the compiler fail to substitute the type before the template is selected as best candidate and the substitution failure is turned into an actual error (and not SFINAE)
No compiler could possibly implement this functionality in a consistent manner. You are simply asking too much.
TBody might be ambiguous, because sample might not be the only type that has a member member. Furthermore, if g calls other template functions, the compiler has no way of knowing what other restrictions might be imposed on TBody.
So in some edge cases, it is theoretically possible to deduce the proper type for TBody, generally it is not.