4

我正在尝试从接受 Callable 类型的模板函数创建一个承诺。但我不知道该怎么做。我尝试使用std::invoke_result_t,但这需要参数来知道结果类型,这是我在构造 promise 时不知道的。

有什么方法可以推断出返回类型?我想在泛型 lambda 的情况下这可能是不可能的,但是对非泛型 lambda 情况有什么作用吗?

template <typename Callable, typename Promise>
class Job {

  public:
    Job(Callable&& c, Promise&& p) 
    : callable(std::move(c))
    , promise(std::move(p))
    {}

    auto getFuture() {
        return /* a std::shared_future */;
    }   

    template<typename... Args>
    void call(Args&&... args) {
        promise.set_value(std::invoke(callable, args...));
    }

  private:
    Callable callable;
    Promise promise;
};

template<typename Callable>
decltype(auto) makeJob(Callable&& c) {
    std::promise</* some type */> promise = /* something */;
    return Job(std::forward<Callable>(c), std::move(promise));
}

int main() {
    f1 = [](int arg){return arg;};
    auto job = makeJob(std::move(f1));
    auto future = job.getFuture();
    job.call(1);
    std::cout << future.get() << '\n';
 }
4

1 回答 1

4

有什么方法可以推断出返回类型?我想在泛型 lambda 的情况下这可能是不可能的,但是对非泛型 lambda 情况有什么作用吗?

你标记了 C++17 所以......std::function并且推理指南是你的朋友。

您可以使用以下内容检测可调用的返回类型

typename decltype(std::function{c})::result_type;

所以你的makeJob()函数可以写成

template <typename Callable>
auto makeJob (Callable && c)
 {
   using retT = typename decltype(std::function{c})::result_type;

   return Job{std::forward<Callable>(c), std::promise<retT>{}};
 }

课堂上也一样Job

显然这是有效的,因为f1

auto f1 = [](int arg){return arg;};

具有不依赖于参数的返回类型;使用通用 lambda

// ..........vvvv
auto f1 = [](auto arg){return arg;};

这个解决方案不再有效,我认为你不能在不知道参数类型的情况下编写一些东西来获取返回类型。

下面是一个完整的编译示例

#include <future>
#include <memory>
#include <iostream>
#include <functional>

template <typename C, typename P>
class Job
 {
   public:
      using retT
         = typename decltype(std::function{std::declval<C>()})::result_type;

      Job (C && c, P && p) : callable{std::move(c)}, promise{std::move(p)}
       { }

      auto getFuture ()
       { return std::shared_future<retT>{ promise.get_future() }; }   

      template <typename ... Args>
      void call (Args && ... args)
       { promise.set_value(std::invoke(callable, args...)); }

   private:
      C callable;
      P promise;
 };

template <typename Callable>
auto makeJob (Callable && c)
 {
   using retT
      = typename decltype(std::function{c})::result_type;

   return Job{std::forward<Callable>(c), std::promise<retT>{}};
 }

int main ()
 {
   auto f1 = [](int arg){return arg;};
   auto job = makeJob(std::move(f1));
   auto future = job.getFuture();

   job.call(42);

   std::cout << future.get() << '\n';
 }
于 2018-08-12T19:34:53.787 回答