Я хочу сделать метод convert
это берет общую функцию bar
(может быть std::function
, lambda
, functor
, …) и преобразует его в std::function<double(std::array<double, 3>)>
, Функция bar
может быть:
std::array<double, 3>
в качестве аргумента и возвращения double
, В этом случае, convert
не сложно написатькод:
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
в качестве аргумента и возвращения double
, Также в этом случае convert
не так уж сложно написатькод:
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;
}
Проблема в том, что я понятия не имею, как объединить эти два convert
методы, или это вообще возможно?
Как уже упоминал Макс, решение заключается в использовании SFINAE проверить какие аргументы F
можно вызвать с помощью:
#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]);
};
}
Я начну с того, как бы написать это в C ++ 17:
template<typename F>
std::function<double(std::array<double, 3>)> convert(F&& f) // <== NB: forwarding ref
{
if constexpr (std::is_invocable_v<F&, std::array<double, 3>) {
// direct case
return std::forward<F>(f);
} else {
// unpacking case
return [f=std::forward<F>(f)](std::array<double, 3> arr) {
return std::apply(f, arr);
};
}
}
В C ++ 14 у вас нет if constexpr
, is_invocable
, или же apply
. Первое можно сделать, просто отправив тег (вы вызываете вспомогательную функцию с помощью std::true_type
или же std::false_type
) и два других могут быть реализованы в C ++ 14 просто отлично, и это действительно полезные вспомогательные функции, которые вам, скорее всего, понадобятся для многих других вещей.