Search code examples
c++templateslambdainitializationstatic-members

Initializing a C++ static member that stores a lambda function


I have defined a struct A with a member f that holds a lambda function. The type is given as a template parameter, and f is initialized in the constructor using an argument to the constructor. The following code has worked well.

template <typename f_t>
struct A {
  f_t f;                                             // (1)
  int k;
  A(f_t arg_f, int arg_k) : f(arg_f), k(arg_k) {}    // (2)
  int g(int x) { return f(f(x)) + k; }
};

Now I want to have a vector of struct A with the same lambda function.

int main() {
  int p, q; std::cin >> p >> q;
  auto f1 = [&](int x) -> int { return p * x + q; };
  auto f2 = [&](int x) -> int { return p * x - q; };
  std::vector<A<decltype(f1)>> vec_a1;               // (3)
  std::vector<A<decltype(f2)>> vec_a2;
  for (int i = 0; i < 10000; i++) {
    int k; std::cin >> k;
    vec_a1.emplace_back(f1, k);
    vec_a2.emplace_back(f2, k);
  }
  // ....

  return 0;
}

With this code, I think that member f of struct A should rather be static to save space. But if I change Line (1) to:

static f_t f;

then, naturally, it cannot be initialized in the constructor. Line (2) produces the following error:

error: ‘f_t A<f_t>::f’ is a static data member; it can only be initialized at its definition

The assignment is not allowed, either, because of the deleted assignment operator. If I add the following after Line (3):

A<decltype(f1)>::f = f1

the following error is reported:

error: use of deleted function 'main(int, char**)::<lambda(int)>& main(int, char**)::<lambda(int)>::operator=(const main(int, char**)::<lambda(int)>&)'

(It seems that it would lead to a linker error but for this error.)

How can I initialize the member f?


Solution

  • To save place, you might redesign to something like:

    template <typename F>
    struct A {
      F f;
      std::vector<int>* v;
      A(F f, std::vector<int>* v) : f(f), v(v) {}
      int g(int i, int x) { return f(f(x)) + v[i]; }
    };
    
    nt main() {
      int p, q; std::cin >> p >> q;
      auto f1 = [&](int x) -> int { return p * x + q; };
      auto f2 = [&](int x) -> int { return p * x - q; };
      std::vector<int> v;
      for (int i = 0; i < 10'000; i++) {
        int k; std::cin >> k;
        v.emplace_back(k);
      }
      A<decltype(f1)> a1(f1, &v);
      A<decltype(f2)> a2(f2, &v);
      // ...
    }
    

    So you store each values f1, f2 and ks only once.

    Whereas you store 10.000 time f1, f2 and each ks twice.

    It might be a little less convenient to use. There are generally a trade-of between the different kind of optimizations (memory/speed) themselves, safety and readability/simplicity.