如何从C++中的std::function签名构造无操作回调?

huangapple go评论90阅读模式
英文:

How to construct no-op callback from std::function signature in C++?

问题

我有一些回调定义,例如:

  1. using TSomeCallback = std::function<ReturnType(Type1, Type2, Type3, )>;

我还有一些接受此回调作为参数的方法:

  1. void SetCallback(TSomeCallback);

我想要定义一个模板,可以直接从 TSomeCallback 实例化一个无操作回调:

  1. void SetCallback(TSomeCallback = GetNoopCallback<TSomeCallback>()); // 或者
  2. void SetCallback(TSomeCallback = GetNoopCallback(TSomeCallback())); // 或者任何其他方式。

我找到了这个答案 - 它很好,但我不知道如何根据我的需求进行改进。

英文:

I have some callback definition like:

  1. using TSomeCallback = std::function&lt;ReturnType(Type1, Type2, Type3, …)&gt;;

Also I have some method that accepts this callback as an argument:

  1. void SetCallback(TSomeCallback);

All I want is to define some template that instantiates no-op callback directly from TSomeCallback:

  1. void SetCallback(TSomeCallback = GetNoopCallback&lt;TSomeCallback&gt;()); // or
  2. void SetCallback(TSomeCallback = GetNoopCallback(TSomeCallback())); // or any other way.

I found this answer - it's good, but I don't know how to improve it for my purpose.

答案1

得分: 4

你可以这样做:

  1. void SetCallback(TSomeCallback = [](auto...){});

但我更推荐这样做:

  1. void SetCallback(TSomeCallback = {})

然后在内部检查回调是否非空。或者也许可以不提供默认参数,如果你不想被回调的话就不调用 SetCallback

英文:

You can do it this way

  1. void SetCallback(TSomeCallback = [](auto...){});

but I would recommend rather

  1. void SetCallback(TSomeCallback = {})

and check for the callback being non-empty inside. Or perhaps don't supply a default parameter and just don't call SetCallback if you don't want to be called back!

答案2

得分: 3

你可以使用 lambda 表达式来构造一个不执行任何操作的 std::function< ... >。只要返回类型是 void,那么这个方法可以工作:

  1. #include <functional>
  2. #include <string>
  3. using namespace std;
  4. using TSomeCallback = std::function<void(int, double, int)>;
  5. int main() {
  6. TSomeCallback tc = [](auto...) {};
  7. tc(42, 12.0, 42);
  8. }
英文:

You can use a lambda to construct a std::function&lt; ... &gt; that does nothing. Provided, the return type is void then this works:

  1. #include &lt;functional&gt;
  2. #include &lt;string&gt;
  3. using namespace std;
  4. using TSomeCallback = std::function&lt;void(int,double,int)&gt;;
  5. int main() {
  6. TSomeCallback tc = [](auto...){};
  7. tc(42,12.0,42);
  8. }

答案3

得分: 2

你可以为返回 void 的函数实现 GetNoopCallback,像这样:

  1. template <class F>
  2. F GetNoopCallback() {
  3. return [](auto&&...){};
  4. }

然后:

  1. void SetCallback(TSomeCallback = GetNoopCallback<TSomeCallback>());
英文:

You can implement GetNoopCallback for void-returning functions like this:

  1. template &lt;class F&gt;
  2. F GetNoopCallback() {
  3. return [](auto&amp;&amp;...){};
  4. }

Then:

  1. void SetCallback(TSomeCallback = GetNoopCallback&lt;TSomeCallback&gt;());

答案4

得分: 1

  1. #include <type_traits>
  2. template <typename result>
  3. requires (std::is_void_v<result> ||
  4. std::is_default_constructible_v<result>)
  5. constexpr auto return_default = [](auto&& ...)
  6. noexcept (std::is_void_v<result> ||
  7. std::is_nothrow_default_constructible_v<result>)
  8. {
  9. if constexpr (std::is_void_v<result>)
  10. return;
  11. else
  12. return result {};
  13. };
  14. std::function<void(int)> f1 = return_default<void>;
  15. auto f2 = std::function<A(B,C)>{return_default<A>};
  16. struct any_function_default{
  17. template<typename result, typename ... args>
  18. requires (std::is_void_v<result> ||
  19. std::is_default_constructible_v<result>)
  20. constexpr operator std::function<result(args ...)> () const {
  21. return [] (auto&& ...) {
  22. if constexpr (std::is_void_v<result>)
  23. return;
  24. else
  25. return result {};
  26. };
  27. };
  28. };
  29. std::function<void(int)> f1 = any_function_default{};
  30. auto f2 = std::function<A(B,C)>{any_function_default{}};
  1. This is the translation of the provided code without the code comments and explanations.
  2. <details>
  3. <summary>英文:</summary>
  4. ```C++
  5. #include &lt;type_traits&gt;
  6. template &lt;typename result&gt;
  7. requires (std::is_void_v&lt;result&gt; ||
  8. std::is_default_costructible_v&lt;result&gt;)
  9. constexpr auto return_default = [] (auto&amp;&amp; ...)
  10. noexcept (std::is_void_v&lt;result&gt; ||
  11. std::is_nothrow_default_costructible_v&lt;result&gt;)
  12. {
  13. if constexpr (std::is_void_v&lt;result&gt;)
  14. return;
  15. else
  16. return result {};
  17. };

Now just cast or use the template variable as rvalue:

  1. std::function&lt;void(int)&gt; f1 = return_default&lt;void&gt;;
  2. auto f2 = std::function&lt;A(B,C)&gt;{return_default&lt;A&gt;};

You can take one step further to remove the need for a return type:

  1. struct any_function_default{
  2. template&lt;typename result, typname ... args&gt;
  3. requires (std::is_void_v&lt;result&gt; ||
  4. std::is_default_costructible_v&lt;result&gt;)
  5. constexpr operator std::function&lt;result(args ...)&gt; () const {
  6. return [] (auto&amp;&amp; ...) {
  7. if constexpr (std::is_void_v&lt;result&gt;)
  8. return;
  9. else
  10. return result {};
  11. };
  12. };
  13. };

Now use any_function_default as the universal default for functions:

  1. std::function&lt;void(int)&gt; f1 = any_function_default{};
  2. auto f2 = std::function&lt;A(B,C)&gt; { any_function_default{} };

huangapple
  • 本文由 发表于 2023年3月31日 16:57:38
  • 转载请务必保留本文链接:https://go.coder-hub.com/75896626.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定