以 std::array 的双打作为参数或双打分别作为参数转换函数
Convert function with std::array of doubles as argument or the doubles separately as arguments
我想创建一个方法 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
方法,或者这是否可能?
正如 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]);
};
}
我将从如何用 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
, or apply
。第一个可以通过标记分派来实现(您可以使用 std::true_type
或 std::false_type
调用辅助函数),另外两个可以在 C++14 中很好地实现,并且是非常有用的辅助函数无论如何,您可能会需要很多其他功能。
我想创建一个方法 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
方法,或者这是否可能?
正如 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]);
};
}
我将从如何用 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
, or apply
。第一个可以通过标记分派来实现(您可以使用 std::true_type
或 std::false_type
调用辅助函数),另外两个可以在 C++14 中很好地实现,并且是非常有用的辅助函数无论如何,您可能会需要很多其他功能。