david11
david11

Reputation: 112

How to pass an overloaded function pointer as an argument without resolving (C++03)

I would like to apply an overloaded function to all elements of a struct like so: (The code below will not compile)

#include <iostream>

typedef struct {
  float float_val;
  int int_val;
} NodeStatus;

template<typename T>
void ApplyToFields(NodeStatus *ns1, NodeStatus *ns2, void (*func)(T, T)) {
  func(ns1->float_val, ns2->float_val);
  func(ns1->int_val, ns2->int_val);
}

template<typename T>
void add_print(T a, T b) {
  std::cout << b + a << std::endl;
}

template<typename T>
void sub_print(T a, T b) {
  std::cout << b - a << std::endl;
}

int main() {
  NodeStatus ns1, ns2;
  ns1.float_val = 2.3;
  ns2.float_val = 25.3;
  ns1.int_val = 2;
  ns2.int_val = 20;
  ApplyToFields(&ns1, &ns2, add_print);
  ApplyToFields(&ns1, &ns2, sub_print);
}

I am new to C++ coming from C. After some research I realize that passing a function pointer is probably not the correct way to do this in C++. I am interested in the best way to accomplish the same purpose as opposed to the literal question I posed which may be impossible. Solutions adhering to C++03 would be ideal. Thanks!

Upvotes: 1

Views: 296

Answers (2)

melak47
melak47

Reputation: 4850

You can create a function object wrapping your function template (or replacing it):

struct add_printer {
    template<typename T>
    void operator()(T a, T b) const {
        add_print(a, b);
    }
};

And then use it like this:

ApplyToFields(&ns1, &ns2, add_printer());

This will delay overload resolution until add_printer's operator() is actually instantiated when it is used in ApplyToFields.

In C++14, you could use a polymorphic lambda: [](auto a, auto b) { add_print(a, b); } which, unlike the function object, can be defined almost anywhere, not just at namespace scope.

Upvotes: 3

Jarod42
Jarod42

Reputation: 217275

With your code, you have to specify which overload you want:

ApplyToFields(&ns1, &ns2, add_print<float>);
ApplyToFields(&ns1, &ns2, sub_print<int>);

or

ApplyToFields<float>(&ns1, &ns2, add_print);
ApplyToFields<int>(&ns1, &ns2, sub_print);

Demo

That you want is a generic functor

template<typename F>
void ApplyToFields(const NodeStatus &ns1, const NodeStatus &ns2, F func) {
  func(ns1.float_val, ns2.float_val);
  func(ns1.int_val, ns2.int_val);
}

struct add_print
{
    template<typename T>
    void operator() (T a, T b) {
        std::cout << b + a << std::endl;
    }
};

Demo

Upvotes: 1

Related Questions