8

Is it possible to accept two different types of lambda function as class members without knowing their template arguments ahead of time?

struct two_functors { std::function<???> a; std::function<???> b; ... }; 

Such that something like this would be possible:

void main(){ vector<two_functors> many_functors; int a = 2; int b = 3; double c = 4.7; double d = 8.4; two_functors add_and_subtract; add_and_subtract.a = [a, b](int x, int y){cout << x + y << endl;}; add_and_subtract.b = [c, d](double x, double y){cout << x - y << endl;}; two_functors multiply_and_divide; multiply_and_divide.a = [c, d](double x, double y){cout << x * y << endl;}; multiply_and_divide.b = [a, b](int x, int y){cout << x / y << endl;}; many_functors.push_back(add_and_subtract); many_functors.push_back(multiply_and_divide); for (auto functors : many_functors){ functors.a(); functors.b(); } } 
10
  • Could be done using templates, I expect...CommentedJun 5, 2013 at 16:45
  • Can two_functors be a class template? Aren't add_and_print.a() and add_and_print.b() incorrect without some arguments to pass as x, y, and s?
    – aschepler
    CommentedJun 5, 2013 at 16:45
  • The only reason to need to declare something ahead is if something else uses it. So you expect some statement to use add_and_print without having any kind of clue what it contains? Do you have an example of what you're trying to do?
    – aschepler
    CommentedJun 5, 2013 at 16:59
  • Nesting is probably irrelevant. You can have a class template nested inside a non-template class.
    – aschepler
    CommentedJun 5, 2013 at 17:01
  • 2
    There is no possible way to make a container of functors with differing argument types useful without a whole lot of wrapping and argument-checking code.
    – aschepler
    CommentedJun 5, 2013 at 17:35

4 Answers 4

4

If you just want to construct two_functors at various times, but execute them later in sequence all at once, you could just use the captured data.

struct two_functors { function<void ()> a; function<void ()> b; }; int main() { vector<two_functors> many_functors; int a = 2; int b = 3; double c = 4.7; double d = 8.4; two_functors add_and_subtract { [a, b](){cout << a + b << endl;}, [c, d](){cout << c - d << endl;} }; two_functors multiply_and_divide { [c, d](){cout << c * d << endl;}, [a, b](){cout << a / b << endl;} }; many_functors.push_back(add_and_subtract); many_functors.push_back(multiply_and_divide); for (auto functors : many_functors){ functors.a(); functors.b(); } } 
1
  • This is actually just what I needed! Thanks, it seems my initial understanding of lambdas was flawed.
    – Eric B
    CommentedJun 5, 2013 at 18:19
2

That's essentially a tuple. You can see how the interface is implemented for that.

template< class F0, class F1 > struct two_functors { F0 func0; F1 func1; }; template< class F0, class F1 > two_functors<F0, F1> make_two_functor( F0&& f0, F1&& f1 ) { // Added [std::forward][2] return two_functors<F0,F1>( std::forward<F0>(f0), std::forward<F1>(f1) ); } 
2
  • auto f1 = []{}; auto result = make_two_functor( f1, f1 ); uses struct members with reference type. I don't think that's what you want.
    – aschepler
    CommentedJun 5, 2013 at 18:30
  • std::make_tuple uses std::decay<Ti>::type as the parameters for the returned tuple. (Ignoring extra logic for std::ref and std::cref.)
    – aschepler
    CommentedJun 5, 2013 at 18:45
0

Not an attempt to answer (I just need the formatting feat), just a variation of Steven's proposal

template<typename A, typename B> two_functors<A,B> make_two_functors(A&& a, B&& b) { return two_functors<A,B> {a, b}; } 

Does that have any downside compared to using std::forward<T>?

Btw - I somehow wish the need for such "makers" would have vanished with C++11.

1
  • without std::forward, it can't accept r-value references properly, and the default move constructor for the struct won't be invoked.CommentedOct 18, 2013 at 16:56
0

An alternative to Steven's answer would be to use an intermediate "umbrella" class.

EDIT: Just compiled an example on g++ (GCC) 4.5.3

 #include <functional> #include <iostream> using namespace std; class myfunction { }; template <typename T> class specificFunction : public myfunction { public: function<T> f; specificFunction(function<T> pf) { f = pf; } }; struct two_functors { myfunction* a; myfunction* b; }; int main() { myfunction* f = new specificFunction<void(int,int)> ([](int a, int b) { cout << a << " - " << b << endl; }); myfunction* f2 = new specificFunction<void(double,int)> ([](double a, int b) { cout << a << " - " << b << endl; }); two_functors tf; tf.a = f; tf.b = f2; ((specificFunction<void(int,int)>*)(tf.a))->f(4,5); ((specificFunction<void(double,int)>*)(tf.b))->f(4.02,5); } 
10
  • Of course, there's no practical way to do anything useful with a myfunction*.
    – aschepler
    CommentedJun 5, 2013 at 17:06
  • @aschepler What do you mean? if instead of a struct you put your functions in a container, this is one way to solve it. Can you explain further your comment?
    – Pedrom
    CommentedJun 5, 2013 at 17:08
  • Sure, you can do add_and_print.a = make_specificFunction( [a,b](int x, int y) { return x+y; } );. But then you can't do (*add_and_print.a)(4,5);, because myfunction has no operator().
    – aschepler
    CommentedJun 5, 2013 at 17:21
  • @aschepler Sure you can, you only need to cast it with the proper signature... Something like ((SpecificConnector<void(int,int)>*)(*add_and_print.a)).f(4,5);
    – Pedrom
    CommentedJun 5, 2013 at 17:24
  • That stuff between < and > is not valid as a template argument.
    – aschepler
    CommentedJun 5, 2013 at 17:28

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.