Search code examples
c++templatesboostc++14template-argument-deduction

Calling two versions of the same template function passed as an argument in C++


I want to call two versions of the same function, in a function. For example:

template<class F>
auto ulp_error(F f, float x)
{
    float f1 = f(x);
    double x2 = x;
    float f2 = static_cast<float>(f(x2));
    return boost::math::float_distance(f1, f2);
}

Now I'd like to call this function via:

ulp_error(std::log, 1.2f);

but I get the following error on clang-1000.11.45.5:

fatal error: no matching function for call to 'ulp_error'
    ulp_error(std::log, 1.2f);
note: candidate template ignored: couldn't infer template argument 'F'

Ok, how about this?

ulp_error<decltype(std::log)>(std::log, 1.2f);

which gives the following error:

fatal error: reference to overloaded function could not be resolved; did you mean to call it?
    ulp_error<decltype(std::log)>(std::log, 1.2f);

How can I pass (say) std::log as an argument to a function and call it with two different types?


Solution

  • Maybe as follows?

    ulp_error([](auto x){ return std::log(x); }, 1.2f);
    

    I mean... std::log is a overloaded function; so using simply std::log (or decltype(std::log) doesn't works because the compiler can't choose the correct version. And you can't pass both of they.

    But passing it inside a generic-template, the corrected version is selected by the type of the x lambda parameter.

    Another possible solution should be casting to the correct type, by example

    ulp_error(static_cast<double(*)(double)>(&std::log), 1.2f);
    

    but (MHO) I find this syntax a little ugly.