8

I'm trying to use a template class with a lambda function parameter. However, I don't understand how to pass the parameter. Here's what I've tried so far:

#include <iostream> using namespace std; template <class F> class A { public: int f(int i) { return F(i); //* } }; int main(int argc, const char * argv[]) { auto f = [](int i){return i+5;}; A<decltype(f)> a; cout << a.f(5); return 0; } 

I get an error in the marked line.

Can someone help?

5
  • Does the type F is needed in the class of only for method f? Commented Sep 3, 2016 at 16:23
  • only the method Commented Sep 3, 2016 at 16:23
  • F is a type (class F), what is the meaning of F(i) then? Commented Sep 3, 2016 at 16:24
  • static operator (works at c#) Commented Sep 3, 2016 at 16:24
  • 2
    Lambdas may be stateful (carrying captures). Your "static method" approach doesn't make much sense in light of this. Commented Sep 3, 2016 at 16:34

3 Answers 3

9

Your example doesn't work because F is a type, not a callable object. The next step is to instantiate it by creating a member variable.

template <class F> class A { F function; public: int f(int i) { return function(i); } }; 

However, that still won't work because lambda default constructors are deleted. That means we need another way to construct function. That can be achieved by passing an argument to A's constructor.

template<typename F> class A { F function; public: A(const F& f) : function(f) {} int f(int i) { return function(i); } }; // ... auto f = [](int i) { return i+5; }; A<decltype(f)> a(f); 

This uses the lambda copy constructor, which isn't deleted.

Live example

If you want it to work with any lambda, you can add some more magic.

template<typename F> class A { F function; public: A(const F& f) : function(f) {} template<typename ...Args> auto f(Args... args) -> std::result_of_t<F(Args...)> { return function(std::forward<Args>(args)...); } }; 

Live example

Sign up to request clarification or add additional context in comments.

Comments

4

If you really want to use template in order to accept any kind of function's signature, then the implementation should be something similar to this:

class A { public: template<typename F, typename... Args> auto f(F&& funct, Args&&... args) { return funct(std::forward<Args...>(args)...); } }; 

That because you've said in the comment:

Q: Does the type F is needed in the class of only for method f?
A: only the method.

Because of that, it should be useless to have a template class, when you can just have a template method.

An here, an example how to call the method which just invoke the "callable object with its parameters", in this case a lambda function:

int main(int argc, char* argv[]) { A a; a.f([](int i) -> int { return i + 5; }, 12); // |------callable object-----------| |argument of function| return 0; } 

Practically, the method f accepts as first argument a "callable object" and as further arguments any parameters requested in order to invoke the first argument.


Additional Notes:

If you want to pass to method f a certain type of signature of function, for example: int (*)(int), then you can avoid using template and pass an object of type std::function.

This is just an example:

#include <functional> class A { public: // method g accept a function which get a integer and return an integer as well. int g(std::function<int(int)> funct, int arg) { return funct(arg); } }; 

2 Comments

Because of that, it should be useless to have a template class, when you can just have a template method. A template method requires the caller to push in the lambda each time. A template class, as an example combined with type-erasure, can hide the actual lambda behind an operator().
@skypjack That's the reason I ask whether he needed template only for method or a class. If the question were more clear about the purpose of the generic class A, it would be more easy to answer with a specific solution
2

It's not enough to define A as inherited from or somehow containing a lambda function, you still have to initialize the subobject when you create an instance of A.
To do that, as an example, you can inherit from the lambda and use A as a callable object.
It follows a minimal, working example:

#include <iostream> using namespace std; template <class F> class A: public F { public: A(F f): F(f) {} }; int main() { auto f = [](int i){return i+5;}; A<decltype(f)> a{f}; cout << a(5); return 0; } 

You don't have to define any function f to execute the lambda.
Anyway, if you want to have a function f to be called as a.f(5), you can define it as it follows:

int f(int i) { return F::operator()(i); } 

Or as it follows:

int f(int i) { return (*this)(i); } 

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.