class to aggregate and evaluate many functions in batch

I am trying implement a class which should be able to store several functions, like int p1(int x) { return ...; } or int p2(int x, int y) { return ...;} and evaluate all of them in the order they were added, just by the call to object(value) . but right now, it's only working for function with one argument. anyone can tell me what I am missing here?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
template<typename T, typename ... Args>
class Function {
private:
  std::vector<std::function<T(T,Args...)>> terms;
public:
  Function(std::initializer_list<std::function<T(T,Args...)>> array) {
    for(long unsigned int i=0; i<array.size(); i++) terms.push_back(std::data(array)[i]);
  }

  T operator()(T t, Args ... args) {
    T result = 0;
    for(long unsigned int i=0; i<terms.size(); i++) result += terms[i](t,args...);
    return result;
  }

  Function<T>& operator=(std::initializer_list<std::function<T(T,Args...)>> array) {
    for(long unsigned int i=0; i<array.size(); i++) terms.push_back(std::data(array)[i]);
    return *this;
  }
};

typedef Function<int> f_int;
typedef Function<float> f_float;
typedef Function<double> f_double;
There may be better ways to doing this kind of stuff.

Perhaps if you're able to explain what it is your trying to achieve, we might be able to provide more targetted advice.
I just want to know if there is a modification that I could make to the class that enable it to work with functions with more of one argument.
Your problem is dealing with type. A function with a different signature will require a duplicated set of members using what you've shown, headed in the wrong direction because you really need a mechanism that is unconstrained. And that's why I didn't take on the question head on.
I thought the Args... in the std::function<T(T,Args...)> could indicate that I wanted use any number of arguments for the functions? What should be the right way to indicate that then?
I'm not sure what you want. Something like this, maybe?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
#include <concepts>
#include <type_traits>
#include <functional>
#include <vector>
#include <iostream>

template <typename T>
  concept additive_semigroup = requires(T x, T y)
  {
    std::regular<T>;
    { x + y  } -> std::convertible_to<T>;
    { x += y } -> std::convertible_to<T>; 
  };
  
template <typename F, 
          typename R = typename std::function<F>::result_type> 
    requires additive_semigroup<R>
  struct Function: std::vector<std::function<F>>
  {
    using result_type = R;
    using base_type = std::vector<std::function<F>>;

    using base_type::base_type;
    
    template <typename... Args>
      result_type operator()(Args const&... args) 
      {
        result_type r{}; 
        for (auto& fn: *this) r += fn(args...); 
        return r;
      }
  };

int main()
{
  auto const sum     = [](int a, int b) { return a + b; };
  auto const product = [](int a, int b) { return a * b; };
  
  Function<int(int, int)> fns{ sum, product }; 
  std::cout << fns(2, 3) << '\n'; // (2 + 3) + (2 * 3) = 11
}
Last edited on
klebermo wrote:
I thought the Args... in the std::function<T(T,Args...)> could indicate that I wanted use any number of arguments for the functions?

Here you specified the template arguments:
1
2
typedef Function<int> f_int;
                  ^

You have specified that
T is int
Args is empty

What you get is essentially a class like this:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class f_int {
private:
  std::vector<std::function<int(int)>> terms;
public:
  f_int(std::initializer_list<std::function<int(int)>> array) {
    for(long unsigned int i=0; i<array.size(); i++) terms.push_back(std::data(array)[i]);
  }

  int operator()(int t) {
    int result = 0;
    for(long unsigned int i=0; i<terms.size(); i++) result += terms[i](t);
    return result;
  }

  f_int& operator=(std::initializer_list<std::function<int(int)>> array) {
    for(long unsigned int i=0; i<array.size(); i++) terms.push_back(std::data(array)[i]);
    return *this;
  }
};


If you instead did
 
typedef Function<int, double, std::string> f_int;
then you would instead be able to store functions that takes three arguments (an int, a double and a std::string).


mbozzi wrote:
I'm not sure what you want. Something like this, maybe? ...

Isn't this essentially the same as what he's already got? Except for the different syntax used to specify the return type and parameter types, and the ability to specify the return type and the type of the first parameter independently.
Last edited on
I figured a working example might help.
But you're right, it's essentially the same.
Registered users can post here. Sign in or register to post.