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:
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;
}
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?
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]);
};
}