Преобразуйте функцию с std :: array of doubles в качестве аргумента или удваивают отдельно в качестве аргументов

Я хочу сделать метод 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 методы, или это вообще возможно?

2

Решение

Как уже упоминал Макс, решение заключается в использовании 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]);
};
}
4

Другие решения

Я начну с того, как бы написать это в 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 просто отлично, и это действительно полезные вспомогательные функции, которые вам, скорее всего, понадобятся для многих других вещей.

5

По вопросам рекламы ammmcru@yandex.ru
Adblock
detector