Search code examples
c++type-conversionc++14std-function

Convert function with std::array of doubles as argument or the doubles separately as arguments


I want to make a method convert that takes a general function bar (can be an std::function, lambda, functor,...) and converts it to an std::function<double(std::array<double, 3>)>. The function bar can either be:

  • a function taking std::array<double, 3> as an argument and returning a double. In this case, convert is not difficult to write:

code:

template<typename F>
std::function<double(std::array<double, 3>)> convert (F& bar)
{
    std::function<double(std::array<double,3>)> bar_converted = bar;
    return bar_converted;
}
  • a function taking three separate doubles as an argument and returning a double. Also in this case, convert is not too difficult to write:

code:

template<typename F>
std::function<double(std::array<double, 3>)> convert(F& bar)
{
    std::function<double(std::array<double,3>)> bar_converted;
    auto array_bar = [bar]( std::array<double, 3> x)->double{ return bar(x[0], x[1], x[2]); };
    bar_converted = array_bar;
    return bar_converted;
}

The problem is that I do not have a clue how to combine these two convert methods, or whether this is even possible?


Solution

  • As Max mentioned, the solution is to use SFINAE to check what arguments F can be called with:

    #include <functional>
    #include <type_traits>
    
    /* Aliases to shorten the following code */
    using BarArray = std::array<double, 3>;
    using BarFunction = std::function<double(BarArray)>;
    
    template <typename F>
    /* Check whether F can be called with BarArray and returns double */
    std::enable_if_t<std::is_same_v<std::result_of_t<F(BarArray)>, double>, BarFunction>
    convert(F bar)
    {
        return bar;
    }
    
    template<typename F>
    /* Check whether F can be called with three doubles and returns double */
    std::enable_if_t<std::is_same_v<std::result_of_t<F(double, double, double)>, double>, BarFunction>
    convert(F bar)
    {
        return [bar](BarArray x) {
            return bar(x[0], x[1], x[2]);
        };
    }