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

Я хочу создать метод 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 ]

0 голосов
/ 25 октября 2018

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

0 голосов
/ 25 октября 2018

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