包装一个功能,该函数采用std :: function< double(doule)>为了传递函数,以获取更多参数

发布于 2025-01-21 22:44:25 字数 8 浏览 0 评论 0原文

continue

Problem

I have a function double subs(std::function<double(double)> func), and I want to wrap it in a new function that looks like this

template<typename... Args> double subsWrap(std::function<double(Args... args)> func)

that applies subs to some function that takes more inputs as

subs( subs( subs( ... func(...) ) ) )

with each subs applied to only one of the arguments of func at a time.

Minimal example

Let's say that we have a function

auto subs = [] (std::function<double(double)> func){return func(2) + func(5.3);};

and we want to apply it to

auto f2=[](double x, double y){return std::sin(x*std::exp(x/y)); };

as

subs( [&f2](double y){ return  subs( [&y,&f2](double x){ return f2(x,y); } ); } ) 

For f2, this is easy, so there is no need for a wrapper. However, if we want to do the same thing for a function of a greater number of arguments (e.g. double(double,double,double,double,double)) things start to become complicated.

There has to be a way to do this automatically, but I am not even sure how to start.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

踏雪无痕 2025-01-28 22:44:25

将variadic lambdas与std :: is_invocable键入特征终止递归呢?

template<class Fn>
double subs_wrap(Fn func) {
    if constexpr (std::is_invocable_v<Fn, double>)
        return subs(func);
    else
        return subs([=](double x) {
            return subs_wrap(
                [=](auto... xs) -> decltype(func(x, xs...))
                { return func(x, xs...); }
            );
        });
}

在这里,需要对lambda进行明确的返回类型规范,以传播“ Invocability”属性。 [=](auto ... xs){返回func(x,xs ...); }在任何数量的参数中都可以正式起见,无论func(x,xs ...)是否可视化。当用nectType明确指定返回类型时,Sfinae跳入。

随着此实现,两种表达式

subs([=](double y) { 
    return subs([=](double x) {
        return f2(x, y);
    });
});

都会

subs_wrap(f2);

产生相同的结果。

有趣的是,使用-O3优化GCC和Clang可以 并用编译时常数替换subs_wrap(f2)。使用std :: function参数编写的类似代码,他们不这样做。


如果要将参数传递给subs(每次递归不同)

,我们该如何进行解压缩。

这是一种实现这一目标的方法,并稍微修改代码:

template<class Fn, class P, class... Ps>
double subs_wrap(Fn func, P p, Ps... ps) {
    if constexpr (std::is_invocable_v<Fn, double>) {
        static_assert(sizeof...(Ps) == 0);
        return subs(func, p);
    }
    else {
        static_assert(sizeof...(Ps) > 0);
        return subs([=](double x) {
            return subs_wrap(
                [=](auto... xs) -> decltype(func(x, xs...))
                { return func(x, xs...); },
                ps...);
        }, p);
    }
}

subs_wrap(f2, p1, p2);

What about using variadic lambdas together with std::is_invocable type trait to terminate recursion?

template<class Fn>
double subs_wrap(Fn func) {
    if constexpr (std::is_invocable_v<Fn, double>)
        return subs(func);
    else
        return subs([=](double x) {
            return subs_wrap(
                [=](auto... xs) -> decltype(func(x, xs...))
                { return func(x, xs...); }
            );
        });
}

Here an explicit return type specification for a lambda is needed to propagate "invocability" property. [=](auto... xs) { return func(x, xs...); } is formally invocable with any number of arguments, no matter whether func(x, xs...) is invocable or not. When the return type is specified explicitly with decltype, SFINAE jumps in.

With this implementation, both expressions

subs([=](double y) { 
    return subs([=](double x) {
        return f2(x, y);
    });
});

and

subs_wrap(f2);

will produce the same result.

It's interesting to note that with -O3 optimization both GCC and Clang can optimize all this code away and replace subs_wrap(f2) with a compile-time constant. With similar code written using std::function arguments they don't do it.


How do we do the unpacking if we want to pass arguments to subs (different for each recursion)

Here is a way to achieve this with a slight modification of code:

template<class Fn, class P, class... Ps>
double subs_wrap(Fn func, P p, Ps... ps) {
    if constexpr (std::is_invocable_v<Fn, double>) {
        static_assert(sizeof...(Ps) == 0);
        return subs(func, p);
    }
    else {
        static_assert(sizeof...(Ps) > 0);
        return subs([=](double x) {
            return subs_wrap(
                [=](auto... xs) -> decltype(func(x, xs...))
                { return func(x, xs...); },
                ps...);
        }, p);
    }
}

subs_wrap(f2, p1, p2);
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文