I'd like to be able to infer the first argument of a callable. I can make it work for free and member functions, but I'm struggling with lambdas. Is there some trick I can use?
Here's an example. Within the match functions below, I want to use the knowledge of T.
template<class T>
void match(void (*)(T*, int)) { /* First */ }
template<class T>
void match(void (T::*)(int)) { /* Second */ }
template<class T>
void match(std::function<void(T,int)>) { /* Third */ }
struct A
{
void f(int) {}
};
void g(A*, int) {}
match(&A::f); // Ok, matches first
match(&g); // Ok, matches second
match([](A*, int) {}); // Not Ok
match([&](A*, int) {}); // Not Ok
You cannot.
template<class T>
void g(T*, int) {}
fails to work
void g(void*, int) {}
void g(std::string**, int) {}
fails to work.
The same problem holds with lambdas.
As a general rule, you can ask "can I invoke X with type Y", you cannot get the signature.
std::function is not a lambda, and a lambda is not a std::function. They are unrelated types, other than the fact you can convert a lambda to a std::function with any compatible signature, just like you can convert any callable object.
If you restrict your problem space enough, you could write a traits class to extract the signature of operator() on the incoming object, and treat that as the arguments to a lambda.
This is a bad idea in C++11, and it generally gets worse in C++14 and C++17. [](auto a, int b){} is a lambda in C++14 (and many C++11 compilers support it), and it has no fixed type for the first argument.
Usually a better approach is to bundle the signature up separately than the callable. This violates DRY (Don't Repeat Yourself) in C++11, but in C++14 the lambda can just take auto&& parameters.
Another approach is to ask the question "which of these types work", which can be done. Usually you don't have an unlimited family of types you are working with, but rather an enumerated set.
I know only a way: pass through a std::function
match(std::function<void(A*, int)>([](A*, int) {}));
match(static_cast<std::function<void(A*, int)>>([&](A*, int) {}));
Related
This question already has answers here:
Why doesn't C++11 implicitly convert lambdas to std::function objects?
(3 answers)
Closed 1 year ago.
In c++17, I have a template function which takes some kind of lambda as input. However it only recognizes those with explicit types and ones using auto are rejected.
Why this is the case and any way to combine auto variables and template function taking lambda with specified form as input?
#include <iostream>
#include <vector>
#include <functional>
using namespace std;
class C {};
vector<C> vec(2);
// ForEach func requires lambda must take Object with type C
// only, while its return type can vary as the function is templated.
template<typename T>
void ForEach(function<T (C a)>& lambda) {
std::for_each(begin(vec), end(vec), lambda);
};
int main()
{
auto
f_add_display4 = [](C i) {
};
std::function<void(C)>
f_add_display3 = f_add_display4;
ForEach(f_add_display3);
// ForEach(f_add_display4); // This line won't compile
}
A std function is not a lambda, and a lambda is not a std function.
Your function takes a std function. So when passed it, it deduces the template arguments to std function. If you pass a lambda, it cannot deduce anything.
Second, std function is a type erasure type, not an interface. Your function attempts to deduce the template argument of the type erasure class. Doing this is an anti pattern.
template<class F>
void ForEach(F lambda) {
std::for_each(begin(vec), end(vec), lambda);
}
this works.
If you want to restruct the F to accepting some signature, in c++20 you can do:
void ForEach(std::invocable<C> auto lambda) {
std::for_each(begin(vec), end(vec), lambda);
}
Or in c++17:
template<std::invocable<C> F>
void ForEach(F lambda) {
std::for_each(begin(vec), end(vec), lambda);
}
There are actually two fundamental issues here which cause the deduction to fail:
The first is that the type of a lambda expression is never std::function<Signature> for any signature Signature. However, your function expects a non-const reference argument. As the types differ a conversion is needed which would be a temporary object and temporary objects never bind to non-const reference. You could fix this issue by using a const reference as argument:
template <typename T>
void ForEach(function<T(C)> const& lambda) { ... }
The other problem is that ForEach takes a conceptually open-ended set of potential arguments. However, the argument you have isn't an immediate match: there is no way to to deduce the type T based on the lambda type to exactly match the function argument. Instead, a conversion is required. The compiler won't try to find what instantion might work as the target of an instantiation, although in this case there is only one choice. The conversion itself would work if you'd specify the target type (and made the previous choice of making the parameter const&:
ForEach<void>(f_add_display4);
I would recommend to not constraint the function to take a function<T(C)> to start with! Compared to using an actual lambda function is most likely a pessimization: while the lambda function is statically typed and can, in general, be optimized well, the same is not true for std::function<Signaure>. While the latter can sometimes be optimized often it isn't. If you want to constraint the function to only accept parameters of type C you can do that with some other approaches, probably involving SFINAE for C++17 compilers or a concept for C++20+.
That is, I'd recommend using
template <typename Fun>
void ForEach(Fun&& lambda) {
...
}
... of, if you want to constrain the function using C++20 concepts
template <typename Fun>
requires requires (Fun lambda, C c) { lambda(c); }
void ForEach(Fun&& lambda) {
...
}
The type of f_add_display3 is not std::function<void(C)>. It is of some unnamed class type (some class with a void operator()(C i)).
You can convert the lamda to a std::function<void(C)> as you do here:
std::function<void(C)> f_add_display3 = f_add_display4;
Though, template argument deduction does not consider implicit conversions.
If you change the argument to be a const reference, then you can specify the template argument explicitly:
template<typename T>
void ForEach(const function<T (C a)>& lambda) {
// ...
};
ForEach<void>(f_add_display4); // This line will compile !
Or you drop the unnecessary conversion to std::function entirely:
template <typename F>
void ForEach(F f) {
std::for_each(begin(vec), end(vec),f);
};
Welcome, this is very rare use-case question.
So, here is what I'm trying to do - lets say I have a variadic template function which takes T ...args and a function type FuncT funcName, so here is what we have so far:
template<typename FuncT, typename ...T>
void myFunction(FuncT (*funcName), T ...args);
Now, I want to store my function at void (*)() (this store functions). This works just fine.
std::deque<void (*)()> functions;
func = functions.front();
func(std::forward<T>(args)...); //args is vardict template argument
Now, I can just pass a function to my function as in:
template<typename FuncT, typename T>
int sharedArgument;
void setArg(int x){
sharedArgument = x;
}
template<typename FuncT>
void myFunction(FuncT funcName){
funcName(sharedArgument);
}
void function(int i){
std::cout << i;
}
int main(){
setArg(5);
myFunction(function);
}
Now, I know this is unnecesary, but i want to present a more complicated problem that im having trouble with.
When i want to store arguemnts, I will probably use std::tuple, its design to store arguments, but
Main question is:
How do i store variable amount of arguments in tuple and then perfectly forward them as normal arguments to some function, so that function receiving
function(std::tupleArgumentsHere...);
will read it as
function(5, 42, "yes", 3.14);
I will use this to store arguments and pass them to std::thread.
Thank you, Cheers.
Use std::apply. It is new in c++17. If you cannot, write your own.
In c++14, make an index sequence the same length as your tuple. Then func(std::get<Is>(std::forward<Tup>(tup))...).
In c++11 do the same thing but write your own index sequence.
std::bind stores the function and the arguments together. It returns a callable object encapsulating a copy of the argument values.
You can also use its "placeholder" facility in case there are additional arguments to add after calling queue.front().
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) {}));
A function named test takes std::function<> as its parameter.
template<typename R, typename ...A>
void test(std::function<R(A...)> f)
{
// ...
}
But, if I do the following:
void foo(int n) { /* ... */ }
// ...
test(foo);
Compiler(gcc 4.6.1) says no matching function for call to test(void (&)(int)).
To make the last line test(foo) compiles and works properly, how can I modify the test() function? In test() function, I need f with type of std::function<>.
I mean, is there any template tricks to let compiler determine the signature of function(foo in example), and convert it to std::function<void(int)> automatically?
EDIT
I want to make this work for lambdas (both stateful and stateless) as well.
It looks like you want to use overloading
template<typename R, typename ...A>
void test(R f(A...))
{
test(std::function<R(A...)>(f));
}
This simple implementation will accept most if not all the functions you will try to pass. Exotic functions will be rejected (like void(int...)). More work will give you more genericity.
std::function implements the Callable interface, i.e. it looks like a function, but that doesn't mean you should require callable objects to be std::functions.
template< typename F > // accept any type
void test(F const &f) {
typedef std::result_of< F( args ) >::type R; // inspect with traits queries
}
Duck typing is the best policy in template metaprogramming. When accepting a template argument, be unspecific and just let the client implement the interface.
If you really need a std::function for example to re-target the variable or something crazy like that, and you know the input is a raw function pointer, you can decompose a raw function pointer type and reconsitute it into a std::function.
template< typename R, typename ... A >
void test( R (*f)( A ... ) ) {
std::function< R( A ... ) > internal( f );
}
Now the user can't pass a std::function because that has been encapsulated within the function. You could keep your existing code as another overload and just delegate to that, but be careful to keep interfaces simple.
As for stateful lambdas, I don't know how to handle that case. They don't decompose to function pointers and as far as I know the argument types cannot be queried or deduced. This information is necessary to instantiate std::function, for better or worse.
This is an old one, and I can't seem to find much on the same topic, so I thought I would go ahead and put in a note.
Compiled on GCC 4.8.2, the following works:
template<typename R, typename... A>
R test(const std::function<R(A...)>& func)
{
// ...
}
However, you can't just call it by passing in your pointers, lambdas, etc. However, the following 2 examples both work with it:
test(std::function<void(int, float, std::string)>(
[](int i, float f, std::string s)
{
std::cout << i << " " << f << " " << s << std::endl;
}));
Also:
void test2(int i, float f, std::string s)
{
std::cout << i << " " << f << " " << s << std::endl;
}
// In a function somewhere:
test(std::function<void(int, float, std::string)>(&test2));
The downside of these should stand out pretty obviously: you have to explicitly declare the std::function for them, which might look a little bit ugly.
That said, though, I threw that together with a tuple that gets expanded to call the incoming function, and it works, just requiring a little bit more of an explicitly saying what you're doing calling the test function.
Example code including the tuple thing, if you want to play with it: http://ideone.com/33mqZA
It's usually ill-advised to accept std::function by value unless you are at 'binary delimitation' (e.g. dynamic library, 'opaque' API) since as you've just witnessed they play havoc with overloading. When a function does in fact take an std::function by value then it's often the burden of the caller to construct the object to avoid the overloading problems (if the function is overloaded at all).
Since however you've written a template, it's likely the case that you're not using std::function (as a parameter type) for the benefits of type-erasure. If what you want to do is inspecting arbitrary functors then you need some traits for that. E.g. Boost.FunctionTypes has traits such as result_type and parameter_types. A minimal, functional example:
#include <functional>
#include <boost/function_types/result_type.hpp>
#include <boost/function_types/parameter_types.hpp>
#include <boost/function_types/function_type.hpp>
template<typename Functor>
void test(Functor functor) // accept arbitrary functor!
{
namespace ft = boost::function_types;
typedef typename ft::result_type<Functor>::type result_type;
typedef ft::parameter_types<Functor> parameter_types;
typedef typename boost::mpl::push_front<
parameter_types
, result_type
>::type sequence_type;
// sequence_type is now a Boost.MPL sequence in the style of
// mpl::vector<int, double, long> if the signature of the
// analyzed functor were int(double, long)
// We now build a function type out of the MPL sequence
typedef typename ft::function_type<sequence_type>::type function_type;
std::function<function_type> function = std::move(functor);
}
As a final note, I do not recommend introspecting functors (i.e. prodding for their result type and argument types) in the general case as that simply don't work for polymorphic functors. Consider several overloaded operator(): then there is no 'canonical' result type or argument types. With C++11 it's better to 'eagerly' accept any kind of functor, or constrain them using techniques like SFINAE or static_assert depending on the needs, and later on (when parameters are available) to use std::result_of to inspect the result type for a given set of arguments. A case where constraining up front is desirable is when the aim is to store functors into e.g. a container of std::function<Sig>.
To get a taste of what I mean by the previous paragraph it's enough to test the above snippet with polymorphic functors.
I've been playing around with C++0x's auto keyword and tried the following.
std::unique_ptr<auto> ptr(new int(0));
I tried compiling it with g++ 4.4.5 and got
error: invalid use of auto
Judging by eye, auto can easily be inferred to int.
My guess is the type inference and the template engine don't talk to each other. Otherwise, the template engine would know to instantiate the template class with int as the type parameter.
Another guess is from the standard, I see this.
A member shall not be declared with auto, extern or register storage class.
But I thought that was the auto as in local variables, not as in auto used to deduce types.
And my last guess is that the compiler thinks this is an auto storage class, not auto for type deduction.
Is there a reason behind this stated in the standard?
That's because it has to determine the class on which to call a constructor before determining what to do with its arguments. If you make the constructor a template, it'll just work like any other template function - auto-deducing arguments.
#dascandy has correctly identified what's wrong with your code. I'll try to provide some rationale:
You're expecting the compiler to infer unique_ptr<int> because the argument is an int*, and unique_ptr<int> has a constructor which accepts int*. For a moment let's ignore the fact that we're using std::unique_ptr, and just talk about a template class we wrote (and can specialize).
Why should the compiler infer unique_ptr<int>? The argument isn't int, it's int*. Why shouldn't it guess unique_ptr<int*>? Of course that would result in a compiler error, since unique_ptr<int*>'s constructor won't accept an int*. Unless I add a specialization:
template<>
class unique_ptr<int*>
{
public:
unique_ptr(int*) {}
};
Now unique_ptr<int*> would compile. How should the compiler know which to choose, unique_ptr<int> or unique_ptr<int*>? What if I add another specialization?
template<>
class unique_ptr<double>
{
public:
unique_ptr(int*) {}
};
The compiler now has three options to choose from, and it has to instantiate the template with every possible argument in order to find them. Clearly this is not feasible, especially with multiple template arguments and template recursion.
What you can do, is make a factory function which connects the inferred type to exactly one template instance:
template<typename T>
std::unique_ptr<T> make_unique(T* arg) { return arg; }
(of course, this won't work because unique_ptr cannot be copied. But the idea is valid, and used in e.g.make_shared and make_pair.)
Some examples of extreme ugliness:
One could argue that unique_ptr<shared_ptr<int>> is a valid match for this code.
Or how about:
template<typename T>
class unique_ptr
{
public:
explicit unique_ptr(T* arg);
unique_ptr(int*, enable_if<(sizeof(T) > 16)>::type* = 0);
};
Just want to add that a solution already exists for most cases:
template <typename T>
std::unique_ptr<T> unique_ptr_auto(T* ptr)
{
// fails to handle std::unique_ptr<T[]>, not deducible from pointer
return std::unique_ptr<T>(ptr);
}
auto ptr = unique_ptr_auto(new int(0));
A bit more verbose, obviously, but you get the idea. These "generator functions" are quite common.
This (or similar) was proposed for the Standard. The proposed functionality looked something like:
std::vector<int> GetMahVector();
std::vector<auto> var = GetMahVector();
However, it was rejected. Why it was rejected, well, you'd have to dig up the relevant Standard process documents, if possible.