Lambda is deduced to std::function if template has no variadic arguments - c++

template<typename ReturnT, typename... ParamT>
void foo(std::function<ReturnT(ParamT...)> callback)
{}
template<typename ReturnT, typename ParamT>
void bar(std::function<ReturnT(ParamT)> callback)
{}
main()
{
foo<int, int>([](int x){ return x; }); // no instance of function
// template matches argument list
bar<int, int>([](int x){ return x; }); // OK
}
The only difference between foo and bar is that foo has variadic arguments. Somehow the compiler is able to convert the lambda to a std::function in bar.
To my understanding, template type deduction doesn't consider type conversions. So shouldn't both fail?

You don't have any deduction for the type parameters of bar, they are fully specified.
You still have the tail of the pack to deduce in foo, and that fails because the lambda isn't a std::function.

template<typename ReturnT, typename... ParamT>
void foo(std::function<ReturnT(ParamT...)> callback)
{}
now, foo<int,int> is foo<ReturnT=int, ParamsT starts with {int}>.
It does not fully specify ParamT. In fact, there is no way to fully specify ParamT.
As an incompletely specified template, deduction occurs, and fails. It doesn't try "what if I just assume the pack doesn't go any further".
You can fix this with:
template<typename ReturnT, typename... ParamT>
void foo(block_deduction<std::function<ReturnT(ParamT...)>> callback)
{}
where block_deduction looks like:
template<class T>
struct block_deduction_helper { using type=T; }:
template<class T>
using block_deduction = typename block_deduction_helper<T>::type;
now deduction is blocked on foo's first argument.
And your code works.
Of course, if you pass in a std::function it will no longer auto-deduce arguments.
Note that deducing the type of a a type erasure type like std::function is usually code smell.
Replace both with:
template<class F>
void bar(F callback)
{}
if you must get arguments, use function traits helpers (there are many on SO). If you just need return value, there are std traits that already work that out.
In c++17 you can do this:
tempate<class R, class...Args>
void bar( std::function<R(Args...)> f ) {}
template<class F>
void bar( F f ) {
std::function std_f = std::move(f);
bar(std_f);
}
using the c++17 deduction guides feature.

Related

How to auto deduct argument and return type of lambda with std::function?

This code:
template<typename Arg, typename Ret>
Ret fun(std::function<Ret(Arg)> fun){
Arg x=0;
return fun(x);
};
auto f=[](int x){return x;};
fun(f); //compilation failed.
doesn't work. I want to get the argument and return type of lambda in fun.
I think the argument type has already known at comile time, why the compilier can't deduct it automaticall?
The problem here is that the lambda is not an std::function, so you're asking the compiler to do a deduction (find the type of Arg AND Ret) and a convertion i.e. convert the lambda to an std::function. The combination causes a conflict.
If you want to still use std::function as argument type for fun, then the easier thing to do is to make a utility that identifies what std::function to cast your callable to, e.g.:
#include <functional>
using namespace std;
template<typename T>
struct memfun_type
{
using type = void;
};
template<typename Ret, typename Class, typename... Args>
struct memfun_type<Ret(Class::*)(Args...) const>
{
using type = std::function<Ret(Args...)>;
};
template<typename F>
typename memfun_type<decltype(&std::decay_t<F>::operator())>::type
function_from(F&& func)
{
return std::forward<F>(func);
}
which you'd use as
fun(function_from(f)); // Auto-detect <Ret(Args...)> types.
Demo
After showing the mechanics of how auto-detection works, note that from C++17 onwards the CTAD feature does this for you. So in newer compilers this also works:
fun(std::function(f)); // Again no types specified.
Alternatively, you can make your f a bit more generic and use just the argument deduction, like:
template <class F>
auto fun(F &&fun)
{
int x=0;
return std::invoke(std::forward<F>(fun), x);
};
fun(f); // Call directly with your lambda
Demo
Using c++20 concepts, this version can be restricted to the argument and input function types that you want.

Template argument and deduction of std::function parameters

Assume there is a template function foo() which accepts an arbitrary number of arguments. Given the last argument is always an std::function, how do I implement a foo() template shown below in a way that CbArgs would contain this std::function's parameters?
template<typename... InArgs, typename... CbArgs = ???>
// ^^^^^^^^^^^^
void foo(InArgs... args) { ... }
For example, CbArgs should be {int,int} if invoked like this:
std::function<void(int,int)> cb;
foo(5, "hello", cb);
My first idea was:
template<typename... InArgs, typename... CbArgs>
void foo(InArgs... args, std::function<void(CbArgs...)>) { ... }
But this does not compile:
note: template argument deduction/substitution failed:
note: mismatched types ‘std::function<void(CbArgs ...)>’ and ‘int’
foo(5, "hello", cb);
Question One:
Why doesn't this compile? Why does the template argument deduction fail?
Eventually, I came up this solution:
template<typename... InArgs, typename... CbArgs>
void fooImpl(std::function<void(CbArgs...)>, InArgs... args) { ... }
template<typename... InArgs,
typename CbType = typename std::tuple_element_t<sizeof...(InArgs)-1, std::tuple<InArgs...>>>
void foo(InArgs... args)
{
fooImpl(CbType{}, args...);
}
Here CbType is the last type in InArgs which is std::function. Then a temporary of CbType is passed to fooImpl() where CbArgs are deduced. This works, but looks ugly to me.
Question Two:
I wonder if there is a better solution without having two functions and a temporary instance of CbType?
Why doesn't this compile? Why does the template argument deduction fail?
When a parameter pack is not the last parameter, it cannot be deduced. Telling the compiler the contents of InArgs... will make your foo definition work:
template<typename... InArgs, typename... CbArgs>
void foo(InArgs..., std::function<void(CbArgs...)>) { }
int main()
{
std::function<void(int,int)> cb;
foo<int, const char*>(5, "hello", cb);
}
Alternatively, as you discovered in your workaround, simply put InArgs... at the end and update your foo invocation:
template<typename... InArgs, typename... CbArgs>
void foo(std::function<void(CbArgs...)>, InArgs...) { }
int main()
{
std::function<void(int,int)> cb;
foo(cb, 5, "hello");
}
I wonder if there is a better solution without having two functions and a temporary instance of CbType?
Here's a possible way of avoiding the unnecessary temporary instance but using your same mechanism for the deduction of CbArgs...: simply wrap CbType in an empty wrapper, and pass that to fooImpl instead.
template <typename T>
struct type_wrapper
{
using type = T;
};
template<typename... InArgs, typename... CbArgs>
void fooImpl(type_wrapper<std::function<void(CbArgs...)>>, InArgs&&...) { }
template<typename... InArgs,
typename CbType =
std::tuple_element_t<sizeof...(InArgs)-1,
std::tuple<std::remove_reference_t<InArgs>...>>>
void foo(InArgs&&... args)
{
fooImpl(type_wrapper<CbType>{}, std::forward<InArgs>(args)...);
}
Additional improvements:
The typename after typename CbType = was unnecessary - it was removed.
args... should be perfectly-forwarded to fooImpl to retain its value category. Both foo and fooImpl should take args... as a forwarding-reference.
wandbox example
Note that there is a proposal that would make dealing with non-terminal parameter packs way easier: P0478R0 - "Template argument deduction for non-terminal
function parameter packs". That would make your original implementation work as intended.

Concept checking a function doesn't work with movable-only arguments

I have a function that calls a callback function that accepts a movable-only type (for example unique_ptr).
template <typename Function>
void foo(const Function& function) {
BOOST_CONCEPT_ASSERT((
boost::UnaryFunction<Function, void, std::unique_ptr<Bar>));
auto bar = std::make_unique<Bar>();
...
function(std::move(bar));
}
Trying to compile this code, I get a message that the BOOST_CONCEPT_ASSERT line tries to copy the unique_ptr. If I remove the line, the code works fine. It seems that the Boost.Concept library does not support move semantics. Is there any workaround for this without writing my own concept class (which, incidentally, would not be very simple to support both lvalues and rvalues as their arguments).
That's correct. Unfortunately, UnaryFunction as a concept is written as:
BOOST_concept(UnaryFunction,(Func)(Return)(Arg))
{
BOOST_CONCEPT_USAGE(UnaryFunction) { test(is_void<Return>()); }
private:
void test(boost::mpl::false_)
{
f(arg); // "priming the pump" this way keeps msvc6 happy (ICE)
Return r = f(arg);
ignore_unused_variable_warning(r);
}
void test(boost::mpl::true_)
{
f(arg); // <== would have to have std::move(arg)
// here to work, or at least some kind of
// check against copy-constructibility, etc.
}
#if (BOOST_WORKAROUND(__GNUC__, BOOST_TESTED_AT(4) \
&& BOOST_WORKAROUND(__GNUC__, > 3)))
// Declare a dummy construktor to make gcc happy.
// It seems the compiler can not generate a sensible constructor when this is instantiated with a refence type.
// (warning: non-static reference "const double& boost::UnaryFunction<YourClassHere>::arg"
// in class without a constructor [-Wuninitialized])
UnaryFunction();
#endif
Func f;
Arg arg;
};
Since arg is passed by lvalue, there's no way to get that to work with Boost.Concepts. Directly. You could write a hack though. Since we're just calling checking that f(arg) is valid, we could construct a local type for arg that is convertible to unique_ptr<Bar>. That is:
template <typename Function>
void foo(Function f)
{
struct Foo {
operator std::unique_ptr<int>();
};
BOOST_CONCEPT_ASSERT((
boost::UnaryFunction<Function, void, Foo>));
f(std::make_unique<int>(42));
}
Or more generally:
template <typename T>
struct AsRvalue {
operator T(); // no definition necessary
};
template <typename Function>
void foo(Function f)
{
BOOST_CONCEPT_ASSERT((
boost::UnaryFunction<Function, void, AsRvalue<std::unique_ptr<int>>>));
f(std::make_unique<int>(42));
}
That compiles for me on gcc and clang (though gives a warning on clang about unused typedefs). However, at that point, it may be clearer to just write out your own concept to get it to work. Something like Piotr's would be easiest.
#include <type_traits>
#include <utility>
template <typename...>
struct voider { using type = void; };
template <typename... Ts>
using void_t = typename voider<Ts...>::type;
template <typename, typename = void_t<>>
struct is_callable : std::false_type {};
template <typename F, typename... Args>
struct is_callable<F(Args...), void_t<decltype(std::declval<F>()(std::declval<Args>()...))>> : std::true_type {};
//...
static_assert(is_callable<Function&(std::unique_ptr<Bar>)>{}, "Not callable");
DEMO

Can someone explain how to use result_of within template?

I'm trying to create a delayable call object. Something along the lines of (pseudo-code):
template <class FN>
struct delayable_call
{
return-type-of-FN call(); // <-- I'd like to use result_of here.
template<class ArgTypes...>
delayable_call(FN* pFn, ArgTypes... args);
FN* fn;
args-saving-struct;
};
I tried using result_of::type for the return type of call, but get errors during instantiation of the template because apparently the argument types need to be specified separately.
Instantiation:
int foo(bool, double); // function prototype.
delayable_call<int(bool, double)> delayable_foo(foo, false, 3.14); // instantiation
The error messages and documentation I've read about result_of seem to indicate that the argument types must also be specified. So instead of result_of<FN>::type, I'd need to specify result_of<FN(bool, double)>::type. This does actually fix the compilation problem I'm having, but breaks the generality of the template.
So, how can I use result_of with a template parameter when the template parameter represents the function signature?
template <class FN> struct delayable_call;
template<class R, class...Args> delayable_call<R(Args...)>{
typedef R(*)(Args...) pFN;
replace your delayable_call with a specialization, and you will extrace both R and Args.... You need Args... anyhow to store the parameters.
However, a library-strength delayable call will end up using type erasure. The easiest way is a simple std::function<R()> where you shove a lambda into it:
int foo(double);
double x = 7;
std::function<int()> delayed_foo = [x]{ return foo(x); }
and capture by value unless you really, really mean it to capture by reference.
You could deduce R via:
template<typename Fn, typename... Args>
std::function< typename std::result_of<Fn(Args...)>::type()>
make_delayed_call( Fn&& fn, Args&&... args ) {
return [=]{ return fn(std::move(args)...); }
}
which should deduce your R from the callable object and the arguments. This captures everything by copy -- capture by move requires either more boilerplate, or C++14.

Why can't C++ infer the template type?

Why can't the compiler figure out these template parameters? Is there a way to make it do so?
(I'm using Visual Studio 2010.)
template<typename T, typename TFunc>
void call(TFunc func) { func(T()); }
void myfunc(void *) { }
int main() { call(myfunc); }
T appears nowhere in the parameter list so T cannot be deduced from the function arguments. All types to be deduced must appear in deduced contexts in the parameter list. For example,
template <typename TReturn, typename TParameter>
void call(TReturn (*f)(TParameter))
{
f(TParameter());
}
Template parameter deduction for function templates only works based on function arguments, nothing else. The function definition is never looked at for the purpose of determining the template parameters, so your parameter T cannot possibly be deduced.
You could remedy your situation by incorporating the type into the function signature: Since you expect the outer function to be called with a function itself, make that explicit:
template <typename T> void foo(void(*f)(T))
{
T x;
f(x);
// ...
}
Combine function overloading with functors, and it becomes impossible in the general case to determine what arguments can be passed to a callable entity.
Consider, for example
struct FunctorExample {
void operator()(int x) {...}
std::string operator()(const std::string& ) {...}
};
If there were some way to coax the compiler to pattern match on arguments, it would have to have undefined or error behavior when applied to FunctorExample.
Instead, the trend seems to be that when you want to template metaprogram with functors, you specify the functor and argument list. Examples (off the top of my head) being boost::result_of and boost::fusion.
Edit: That said, if you're willing to restrict your attention somewhat, and you can use some C++11 syntax (decltype), you can arrange to introspect a bit more:
// Support functors with a very simple operator():
template <typename T> struct argument :
public argument<decltype(&T::operator())> {};
// Pointers to member functions
template <typename C, typename R, typename A> struct argument<R(C::*)(A)>
{typedef A type;};
// Function types
template <typename R, typename A> struct argument<R(A)> {typedef A type;};
// Function pointer types.
template <typename R, typename A> struct argument<R(*)(A)> {typedef A type;};
// Now for call:
template <typename FuncType>
void call(FuncType func) {
typedef typename argument<FuncType>::type Arg;
func(Arg());
}
// example:
class FunctorInt {public: int operator()(int ) {return 0;};};
void myfunc(void *) {}
int main() {
call(myfunc);
call(FunctorInt());
}
Variadic templates could be used to expand this stuff to support more than one argument.