如何创建一个模板,用于接受回调的两个不同签名。

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

How to create a template that takes two different signatures for a callback

问题

Here's the translated content you requested:

我有一个执行器,它接受一个要运行的函数。它支持两种签名,取决于回调函数是否需要会话对象。

template<typename T, typename S>
T run(const std::function<T(Client&)>& f, S s);

template<typename T, typename S>
T run(const std::function<T(Client&, const S&)>& f, S s);

我想要有一个函数来包装这两个函数(比如用于重试),但我不想重复编写它们,因为它们是相同的:

template <typename T, typename S>
T runWithRetry(const std::function<T(Client&)>& f, S s) {
  for (;;) {
    try {
      return run(f, s);
    } catch (Retry &e) {}
  }
}

template <typename T, typename S>
T runWithRetry(const std::function<T(Client&, const S&)>& f, S s) {
  for (;;) {
    try {
      return run(f, s);
    } catch (Retry &e) {}
  }
}

这是我想要解决的实际问题。

我尝试将回调函数设为模板,但随后我需要一种获取返回类型的方法:

template <typename F, typename S>
return_type<F>::type runWithRetry(const F& f, S s);

那么如何实现return_type?我想要类似以下的东西:

template <typename F, typename S> struct return_type {
  using type = decltype(std::declval<F>(std::declval<Client>)) || decltype(std::declval<F>(std::declval<Client>, std::declval<S>))
}

但我无法弄清楚如何表达它。

我可以使用C++20。

英文:

I have an executor that takes a function to run. It supports two signatures depending on whether the callback wants the session object.

template&lt;typename T, typename S&gt;
T run(const std::function&lt;T(Client&amp;)&gt;&amp; f, S s);

template&lt;typename T, typename S&gt;
T run(const std::function&lt;T(Client&amp;, const S&amp;)&gt;&amp; f, S s);

I want to have a function wrap these two (say for retries) but I don’t want to write it twice since they are the same:

template &lt;typename T, typename S&gt;
T runWithRetry(const std::function&lt;T(Client&amp;)&gt;&amp; f, S s) {
  for (;;) {
    try {
      return run(f, s);
    } catch (Retry &amp;e) {}
  }
}

template &lt;typename T, typename S&gt;
T runWithRetry(const std::function&lt;T(Client&amp;, const S&amp;)&gt;&amp; f, S s) {
  for (;;) {
    try {
      return run(f, s);
    } catch (Retry &amp;e) {}
  }
}

This is the actual problem I want to solve.

I tried making the callback a template but then I needed a way to get the return type:

template &lt;typename F, typename S&gt;
return_type&lt;F&gt;::type runWithRetry(const F&amp; f, S s);

So how to implement return_type? I wanted something like:

template &lt;typename F, typename S&gt; struct return_type {
  using type = decltype(std::declval&lt;F&gt;(declval&lt;Client&gt;)) || decltype(std::declval&lt;F&gt;(declval&lt;Client&gt;, declval&lt;S&gt;)
}

But I couldn’t figure out how to express that.

I can use C++20.

答案1

得分: 4

如果您可以使用C++20,那么您无需担心返回类型,它可以使用auto进行推断。这将给您提供:

template <typename F, typename S>
auto runWithRetry(const F& f, S s) {
  for (;;) {
    try {
      return run(f, s);
    } catch (Retry &e) {}
  }
}

现在返回类型将是run(f, s)的推断返回类型。如果run可以返回引用,并且您希望保留它,那么您需要将返回类型更改为decltype(auto),而不仅仅是auto

英文:

If you can use C++20, then you don't need to worry about the return type, it can be deduced for you using auto. That gives you

template &lt;typename F, typename S&gt;
auto runWithRetry(const F&amp; f, S s) {
  for (;;) {
	try {
	  return run(f, s);
	} catch (Retry &amp;e) {}
  }
}

And now the return type will be the deduced return type of run(f, s). If run can return a reference, and you want to keep that, then you need to use decltype(auto) as the return type instead of just auto.

huangapple
  • 本文由 发表于 2023年5月18日 04:40:53
  • 转载请务必保留本文链接:https://go.coder-hub.com/76276051.html
匿名

发表评论

匿名网友

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

确定