我想制作一个具有通用功能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
方法,或者是否有可能?
答案 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 constexpr
,is_invocable
或apply
。第一个可以通过仅执行标签分发来实现(您可以使用std::true_type
或std::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]);
};
}