高阶功能的功能签名

发布于 2025-02-10 17:35:31 字数 351 浏览 2 评论 0 原文

定义将函数作为参数的函数时,按值和通用参考进行函数参数有什么区别? (即):

template <typename Fn,typename... Args>
void apply(Fn&& fn, Args &&... args);

或者

template <typename Fn,typename... Args>
void apply(Fn fn, Args &&... args);

也许问题是:函数模板参数是否应该是最大化通用性的通用引用?或举例说明两个签名都会产生不同的行为。

When defining a template function taking a function as parameter, what is the difference between taking the function parameter by value and by universal reference ?
(i.e) :

template <typename Fn,typename... Args>
void apply(Fn&& fn, Args &&... args);

and

template <typename Fn,typename... Args>
void apply(Fn fn, Args &&... args);

Or maybe the question is : should the function template parameter be an universal reference to maximize genericity ? Or give example where both signature would give different behaviour.

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

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

发布评论

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

评论(2

饭团 2025-02-17 17:35:31

如果您只通过功能,我相信几乎没有区别。在这两种情况下,功能都将首先转换为功能指针。

如果要通过a std :: function 一样,情况会变得不同。如果按值呼叫,将有一个副本。有时也许这不是您的期望。
例如

struct Callable {
    ...
    Callable(const& Callable); // maybe expensive to copy
    void operator()();
};

template <typename Fn,typename... Args>
void apply_v(Fn fn, Args &&... args);


template <typename Fn,typename... Args>
void apply_ur(Fn&& fn, Args &&... args);

Callable c;
// do something to c
apply_v(c); // may be less effective
apply_ur(c);
apply_ur(std::move(c));

,我相信这确实取决于您的情况。

也许您可以看一下STL的签名,看来他们倾向于进行普遍参考。

例如 std :: bind

template< class F, class... Args >
constexpr /*unspecified*/ bind( F&& f, Args&&... args );

或约束 std :: thread :: thread

template< class Function, class... Args >
explicit thread( Function&& f, Args&&... args );

If you only pass functions, I believe there's little difference. In both cases, function will be first converted to function pointers.

If you're to pass a FunctionObject, like a lambda or std::function, things will become different. There'll be a copy if call by value. Sometimes maybe it's not what you expect.
e.g.

struct Callable {
    ...
    Callable(const& Callable); // maybe expensive to copy
    void operator()();
};

template <typename Fn,typename... Args>
void apply_v(Fn fn, Args &&... args);


template <typename Fn,typename... Args>
void apply_ur(Fn&& fn, Args &&... args);

Callable c;
// do something to c
apply_v(c); // may be less effective
apply_ur(c);
apply_ur(std::move(c));

But it really depends on your situation, I believe.

Maybe you can take a look at the signiture in STL, it seems they tend to take a universal reference.

e.g. std::bind

template< class F, class... Args >
constexpr /*unspecified*/ bind( F&& f, Args&&... args );

or construtor of std::thread

template< class Function, class... Args >
explicit thread( Function&& f, Args&&... args );
韶华倾负 2025-02-17 17:35:31

关于参数类型的大多数一般考虑也适用于传递可可。我将您推荐给您的核心准则

或举例说明两个签名都会产生不同的行为。

考虑 operator()可以基于l/r-valueness超载:

#include <utility>
#include <iostream>

struct foo {
    void operator()() const & { std::cout << "hello "; }
    void operator()() && { std::cout << "world\n";}
};

template <typename F> void apply1(F&& f) { std::forward<F>(f)(); }
template <typename F> void apply2(F f) { f(); }


int main() {
    foo f;
    std::cout << "apply1\n";
    apply1(f);
    apply1(foo{});
    std::cout << "apply2\n";
    apply2(f);
    apply2(foo{});
}

apply1
hello world
apply2
hello hello 

Most general considerations for type of arguments apply to passing callables as well. I refer you to the core guidelines https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#fcall-parameter-passing.

Or give example where both signature would give different behaviour.

Consider that operator() can be overloaded based on l/r-valueness:

#include <utility>
#include <iostream>

struct foo {
    void operator()() const & { std::cout << "hello "; }
    void operator()() && { std::cout << "world\n";}
};

template <typename F> void apply1(F&& f) { std::forward<F>(f)(); }
template <typename F> void apply2(F f) { f(); }


int main() {
    foo f;
    std::cout << "apply1\n";
    apply1(f);
    apply1(foo{});
    std::cout << "apply2\n";
    apply2(f);
    apply2(foo{});
}

Output:

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