1

Consider the following code, which is contained in a library of my making.

#include <complex>

std::complex<double> besselJ(int order, std::complex<double> z)
{
    // Function call
}

std::complex<double> besselH1(int order, std::complex<double> z)
{
   // Function call
}

Notice that both functions have the same signature. Now, I want to write a third function that does exactly the same thing whether it's acting on besselJ or besselH1. I tried the following

template<std::complex<double> (*T)(int, std::complex<double>)>
std::complex<double> diffBessel(int order, std::complex<double> z)
{
    return T(order-1, z)-T(order+1,z);
}

When a member function tries to use the syntax diffbessel<besselJ>(int, std::complex<double>, GCC complains that the value of 'besselJ' is not usable in a constant expression. See this answer for an explanation.

Is there a way to do something like the templated code above would do if it worked without resorting to wrapping besselJ and besselH1 in structs? I think structs would add unneeded complexity.

UPDATE: This works beautifully, as @aschepler suggested it should. There was a name collision in the actual code. It took that extra 1001th look to see it. I had been confused by other StackOverflow articles which suggested that this wouldn't work because the function pointer was mutable.

Community
  • 1
  • 1
Joey Dumont
  • 898
  • 2
  • 7
  • 25

2 Answers2

4

PREMISE:

Provided that besselJ in your example is the name of the function, and not of a variable you are using as a template argument, then passing a function pointer as a non-type template argument should work.

See a live example.

ALTERNATIVE SOLUTION:

If your function pointer is held in a variable whose value is computed at run-time, you won't be allowed to use that function pointer as a template argument. If you want to use a run-time function pointer, you could just use a regular function argument rather than a template argument:

#include <complex>

std::complex<double> diffBessel(
    std::complex<double> (*fxn)(int, std::complex<double>),
    int order,
    std::complex<double> z
    )
{
    return fxn(order-1, z) - fxn(order+1,z);
}

MORE IDIOMATIC SOLUTION: (requires C++11)

If you want more flexibility, with C++11 you could use std::function<>:

#include <complex>
#include <functional>

std::complex<double> diffBessel(
    std::function<std::complex<double>(int, std::complex<double>)> fxn,
    int order,
    std::complex<double> z
    )
{
    return fxn(order-1, z)- fxn(order+1,z);
}

In both cases, your function could be invoked this way:

int main()
{
    std::complex<double> c;
    /* ... */
    diffBessel(besselH1, 2, c);
}

FURTHER POSSIBILITY:

As a further possibility, if you do not want or cannot use std::function<>, you could let your function accept any callable object by making it a template:

template<typename F>
std::complex<double> diffBessel(
    F f,
    int order,
    std::complex<double> z
    )
{
    return f(order-1, z) - f(order+1,z);
}

Again, you would invoke this exactly the same way as you invoked the previous versions.

Andy Prowl
  • 124,023
  • 23
  • 387
  • 451
  • I thought of using `std::function`, but in the [article](http://stackoverflow.com/questions/9054774/difference-between-stdfunction-and-a-standard-function-pointer) comparing `std::function` and function pointers, it is discouraged to use `std::function` unless the extra power is needed. – Joey Dumont Mar 07 '13 at 22:16
  • @JoeyDumont: The decision on whether or not to use `std::function` is based on your use cases mainly. `std::function` allows for more flexibility (you can pass in a lambda, a functor, anything), and its "bad" performance (a virtual function call in most cases) should become an issue for you only when you prove it to be a bottleneck. Otherwise, you should focus on clean design. This said, you do not *have* to use `std::function`. You could use a regular function pointer, but as a function argument, not as a template argument. – Andy Prowl Mar 07 '13 at 22:20
  • @JoeyDumont: Anyway, as I wrote at the beginning of the answer, a template argument should also work in your case, as long as you are not passing in the value of a *variable*. If you are, i.e. if the function to be used is determined at run-time, then you're pretty much forced to use a function argument rather than a template argument: whether to opt for a regular pointer or an `std::function` is up to you. Personally, I would go for the second one. – Andy Prowl Mar 07 '13 at 22:21
  • @JoeyDumont: There's one more possibility: make your function a template *and* accept the function as a function argument. See the last update to my answer. – Andy Prowl Mar 07 '13 at 22:25
  • Doesn't that last possibility imply that the functions should be in a `struct` or `class`? – Joey Dumont Mar 07 '13 at 22:27
  • @JoeyDumont: No, the last possibility accepts anything which is a callable object. Could be a function pointer, or the instance of a functor class. – Andy Prowl Mar 07 '13 at 22:29
3

Templates need to know their parameters at compile time. Pulling the template parameter out of a variable at runtime won't work.

Just make the function pointer a function parameter. It doesn't need to be a template function.

std::complex<double> diffBessel(int order,
                                std::complex<double> z,
                                std::complex<double> (*T)(int, std::complex<double>))
Drew Dormann
  • 59,987
  • 13
  • 123
  • 180
  • Indeed, but this fails as I have another function that uses either the base functions `diffBessel`. I would need a variable number of function pointers, and that's awfully inelegant at best. Thanks for the idea, though. – Joey Dumont Mar 07 '13 at 22:11