BeeOnRope
BeeOnRope

Reputation: 64997

Passing a generic function to operate on homogenous types

Let's say I have a class composed of homogeneous types:

struct Homog {
    int a;
    double b;
    std::string c;
};

Here's a function which calculates the "element-wise min"1 of two instances of this class:

Homog min(const Homog& l, const Homog& r) {
  return {
      std::min(l.a, r.a),
      std::min(l.b, r.b),
      std::min(l.c, r.c),
  };
}

Great.

Now I want to calculate the max instead of the min. The code is identical, but with std::min replaced with std::max. I wouldn't want to duplicate it, rather I'd like to have one generic "element-wise apply" method, and then the min and max just call that with the appropriate functor:

Homog apply(const Homog& l, const Homog& r, ?? op) {
  return {
      op(l.a, r.a),
      op(l.b, r.b),
      op(l.c, r.c),
  };
}

Homog min(const Homog& l, const Homog& r) {
    return apply(l, r, std::min);
}

Homog max(const Homog& l, const Homog& r) {
    return apply(l, r, std::max);
}

Of course, the above code doesn't work, because I don't know how to declare op. It is not a normal generic functor object, because it needs to work on different types.

Can I do what I want to, somehow passing something which says "call op for each member: don't worry, it will resolve to something for each type"?


Maybe using min() isn't the best name here, because it doesn't behave the same as std::min which always returns one of the two given objects: this method returns a new object which in general is not the same as either of the two inputs, but rather a mix of their member values.

Upvotes: 1

Views: 90

Answers (1)

max66
max66

Reputation: 66240

Of course, the above code doesn't work, because I don't know how to declare op. It is not a normal generic functor object, because it needs to work on different types.

This problem is usually bypassed using a functional, with a template operator().

Starting from C++14 (that introduce generic lambdas) simply as follows

template <typename F>
Homog apply(const Homog& l, const Homog& r, F const & op) {
  return {
      op(l.a, r.a),
      op(l.b, r.b),
      op(l.c, r.c),
  };
}

Homog min(const Homog& l, const Homog& r) {
    return apply(l, r, [](auto const & a, auto const & b){ return std::min(a, b); });
}

Upvotes: 2

Related Questions