转换函数,将 std::数组的双精度作为参数或双精度作为参数单独转换

Convert function with std::array of doubles as argument or the doubles separately as arguments

本文关键字:转换 参数 双精度 单独 数组 函数 std      更新时间:2023-10-16

我想做一个方法convert,它接受一个通用函数bar(可以是std::functionlambdafunctor,...(并将其转换为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方法结合起来,或者这是否可能?

我将从如何在 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 中很好地实现,并且是非常有用的帮助程序函数,无论如何您都可能需要很多其他事情。

正如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]);
};
}