将std :: array的double用作参数或将double分别用作参数来转换函数

时间:2018-10-25 16:00:40

标签: c++ type-conversion c++14 std-function

我想制作一个具有通用功能convert(可以是barstd::functionlambda等的方法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 :(得分:5)

我将从在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 constexpris_invocableapply。第一个可以通过仅执行标签分发来实现(您可以使用std::true_typestd::false_type调用帮助程序函数),另外两个可以在C ++ 14中很好地实现,并且确实是有用的帮助程序无论如何,您可能还需要许多其他功能。

答案 1 :(得分:4)

正如Max所提到的,解决方案是使用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]);
    };
}