james
james

Reputation: 1155

Alias to a function template specialization

int f1(int a, int b) { return a+b; }
int f2(int a, int b) { return a*b; }

template <typename F> void foo(int i, int j)
{
 // do some processing before
 F(i,j);  
 // do some processing after 
}

I want to make an alias to a specialization of foo like this:

constexpr auto foo1 = &foo<f1>;
constexpr auto foo2 = &foo<f2>;

and call the function like this: foo1(1,2);foo2(1,2); Any way to achieve this in C++? Thanks!


Edit: foo() is not a wrapper of f1, it is a function that calls f1 or f2. I need to do something extra before and after the call. F is a functor and I want a 'short cut' to the specialization of foo. The code above is kind of psuedo code.

Upvotes: 5

Views: 3000

Answers (2)

dfrib
dfrib

Reputation: 73176

The accepted answer is spot-on for the OP's request. To complement that answer: an alternative method could be letting the int(int, int) function pointer be an additional argument to the function (in which case we needn't use template techniques), and use std::bind to set up the different default case functions to be used.

#include <iostream>
#include <functional>

int f1(int a, int b) { return a+b; }
int f2(int a, int b) { return a*b; }
int f3(int a, int b) { return a-b; }

void foo(int i, int j, int (*f)(int, int)) {
  // do some processing before
  std::cout << f(i, j) << std::endl;
  // do some processing after
}

int main()
{
  const auto foo1 = std::bind(foo, std::placeholders::_1, std::placeholders::_2, &f1);
  const auto foo2 = std::bind(foo, std::placeholders::_1, std::placeholders::_2, &f2);

  foo1(5, 5);     // 10
  foo2(5, 5);     // 25
  foo(5, 5, &f3); // 0

  return 0;
}

A variation of the above could allow using function wrappers (std::function) to store the help functions as values, in cases these would, for some reason, risk going out of scope prior to the caller objects (foo1, foo2, ...).

void foo(int i, int j, const std::function<int(int, int)> f) { /* ... */ }

// ...

const auto foo1 = std::bind(foo, std::placeholders::_1, std::placeholders::_2, f1);
const auto foo2 = std::bind(foo, std::placeholders::_1, std::placeholders::_2, f2);

Upvotes: 1

AndyG
AndyG

Reputation: 41092

There are some good approaches in the comments: std::bind, using a lambda, passing an instance of F into the function, so I'll provide an alternative.

If the function type that you will pass into foo will always be int(int, int), then you make the template parameter be a non-type template parameter, and then instantiate it with one of your functions:

int f1(int a, int b) { std::cout<<"f1\n"; return a+b; }
int f2(int a, int b) { std::cout<<"f2\n"; return a*b; }

template <int(*F)(int, int)> 
void foo(int i, int j)
{
    F(i,j);   
}

And then call it like so:

int main()
{
    constexpr auto foo1 = foo<f1>;
    constexpr auto foo2 = foo<f2>;
    foo1(1,2);
    foo2(1,2);
}

Output:

f1
f2

The trick we're doing here is that we're making the template parameter be a reference to a function, which is hacky but legal AFAIK.

Demo

Upvotes: 6

Related Questions