Explicit call of the variational function template with an empty parameter package

Consider this simple (bad) function template for which there are many variations on this site:

template <typename R, typename... Args> R call_with(std::function<R(Args...)> f, Args... args) { return f(args...); } 

And two attempts to call it:

 call_with([]{}); // (a) call_with<void>([]{}); // (b) 

I cannot call (a) because lambda is not std::function<R(Args...)> , so template output is not executed. Direct.

However, (b) also fails. I suspect this is because the compiler cannot determine what I mean by providing all the arguments and type reasons that I just provide R , so it tries (and fails) to output Args... for the same reason that initial call failed.

Is there a way to explicitly indicate that I am providing all template arguments? To clarify, I’m only interested in how to explicitly provide the template arguments so that there is no template output - I’m not looking for the right way to write call_with or for the way to create the template the deduction succeeds when called by the lambda.

+8
c ++ c ++ 11 templates template-deduction
source share
2 answers

The short answer to your question is the edited question: if you cannot change the declaration of call_with() , then either use the cast type demonstrated by @CoffeeandCode, or use the method described below to create a wrapper for call_with() .

The problem is that the compiler is trying to infer the template arguments from the first argument of the function. You can prevent this if you write your code like this :

 #include <functional> #include <iostream> // identity is a useful meta-function to have around. // There is no std::identity, alas. template< typename T> struct identity { using type = T; }; template <typename R, typename... Args> R call_with( typename identity<std::function<R(Args...)>>::type f, Args... args) { return f(args...); } int main() { call_with<void>([](int){ std::cout << "called" << std::endl; }, 2); } 

Using the template meta-function to β€œgenerate”, the type std :: function means that the compiler cannot even try to infer the type of the function from the first argument, and it will only use other arguments.

You still need to explicitly specify the return type, but for other arguments you can now choose whether to explicitly specify them or leave it to the compiler to deduce them from the arguments given.

If you really want to ensure that all template arguments are provided and not output, you can also wrap the argument package when calling identity as follows:

 template <typename R, typename... Args> R call_with( typename identity<std::function<R(Args...)>>::type f, typename identity<Args>::type... args) 

In general, if you want the compiler not to output function template argument types that also appear as function parameters, wrap them in a meta function such as identity .

+4
source share

You can specify the type of function in advance, for example:

 int main(){ std::function<void()> f = []{}; call_with(f); } 

or, in a slightly more dirty, but more compact way:

 int main(){ call_with(static_cast<std::function<void()>>([]{})); } 

This is because the compiler does not know what type of return value and arguments to print for the parameters of your template before you ask it to implicitly convert lambda, which is an undefined function object defined by the compiler, to std::function with these template parameters.

Indeed, you just need to change the warpper function as a more general one:

 template<typename Functor, typename ... Args> auto wrapper(Functor &&f, Args &&... args) -> decltype(f(std::forward<Args>(args)...)){ return f(std::forward<Args>(args)...); } 

This should work for any function or type of functor. This is also a really good example of using return types.

Here is a living example

0
source share

All Articles