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

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

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

问题

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

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

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

void SetCallback(TSomeCallback);

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

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

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

英文:

I have some callback definition like:

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

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

void SetCallback(TSomeCallback);

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

void SetCallback(TSomeCallback = GetNoopCallback&lt;TSomeCallback&gt;());  // or
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

你可以这样做:

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

但我更推荐这样做:

void SetCallback(TSomeCallback = {})

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

英文:

You can do it this way

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

but I would recommend rather

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,那么这个方法可以工作:

#include <functional>
#include <string>
using namespace std;

using TSomeCallback = std::function<void(int, double, int)>;

int main() {
    TSomeCallback tc = [](auto...) {};
    tc(42, 12.0, 42);
}
英文:

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

#include &lt;functional&gt;
#include &lt;string&gt;
using namespace std;
     
using TSomeCallback = std::function&lt;void(int,double,int)&gt;;
     
int main() {
    TSomeCallback tc = [](auto...){};
    tc(42,12.0,42);
}

答案3

得分: 2

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

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

然后:

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

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

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

Then:

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

答案4

得分: 1

#include <type_traits>

template <typename result>
requires (std::is_void_v<result> ||
          std::is_default_constructible_v<result>)
constexpr auto return_default = [](auto&& ...)
noexcept (std::is_void_v<result> ||
          std::is_nothrow_default_constructible_v<result>)
{
    if constexpr (std::is_void_v<result>)
        return;
    else
        return result {};
};

std::function<void(int)> f1 = return_default<void>;
auto f2 = std::function<A(B,C)>{return_default<A>};

struct any_function_default{
    template<typename result, typename ... args>
    requires (std::is_void_v<result> ||
              std::is_default_constructible_v<result>)
    constexpr operator std::function<result(args ...)> () const {
        return [] (auto&& ...) {
               if constexpr (std::is_void_v<result>)
                   return;
               else
                   return result {};
        };
    };
};

std::function<void(int)> f1 = any_function_default{};
auto f2 = std::function<A(B,C)>{any_function_default{}};

This is the translation of the provided code without the code comments and explanations.

<details>
<summary>英文:</summary>

```C++
#include &lt;type_traits&gt;

template &lt;typename result&gt;
requires (std::is_void_v&lt;result&gt; ||
          std::is_default_costructible_v&lt;result&gt;)
constexpr auto return_default = [] (auto&amp;&amp; ...)
noexcept (std::is_void_v&lt;result&gt; ||
          std::is_nothrow_default_costructible_v&lt;result&gt;)
{
    if  constexpr (std::is_void_v&lt;result&gt;)
        return;
    else
        return result {};
};

Now just cast or use the template variable as rvalue:

std::function&lt;void(int)&gt; f1 = return_default&lt;void&gt;;
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:

struct any_function_default{
    template&lt;typename result, typname ... args&gt;
    requires (std::is_void_v&lt;result&gt; ||
              std::is_default_costructible_v&lt;result&gt;)
    constexpr operator std::function&lt;result(args ...)&gt; () const {
        return [] (auto&amp;&amp; ...) {
               if  constexpr (std::is_void_v&lt;result&gt;)
                   return;
               else
                   return result {};
        };
    };
};

Now use any_function_default as the universal default for functions:

std::function&lt;void(int)&gt; f1 = any_function_default{};
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:

确定