【问题标题】:Vector of generalized lambdas广义 lambda 向量
【发布时间】:2014-10-11 22:11:21
【问题描述】:

假设我们有这样的代码:

std::vector<std::function<void()>> tasks;

我们添加一个这样的任务:

tasks.push_back([]()
{
    // ...
}

这行得通。但现在我们要添加该任务:

std::unique_ptr<int> v(new int(10));
tasks.push_back([v = std::move(v)]()
{
    // ...
}

而且这段代码没有被编译。

为了更清楚:

std::unique_ptr<int> v(new int(10));
std::function<void()> test = [v = std::move(v)]()
{
};

有编译错误。因为 lambda 的类型不是std::function&lt;void()&gt;。 但是是什么类型的呢?

【问题讨论】:

  • 一个 lambda 具有由编译器生成的“不可提及”的唯一类型。你的问题是std::function要求其函数对象为CopyConstructible,而unique_ptr不能被复制。
  • 但在示例中lambda 是一个右值引用,它调用移动构造函数。不是吗?
  • 没关系。 std::functionCopyConstructible 使用的函数对象有一个硬性要求,而您的 lambda 不是因为它捕获了 unique_ptr。故事结束。

标签: c++ function c++11 lambda c++14


【解决方案1】:

没有 lambda 是 std::functionstd::function 是一个类型擦除器——它使用签名获取任何可销毁、可复制和可调用的内容,然后擦除类型的其余部分。

由于您的 lambda 无法复制,因此无法将其存储在 std::function 中。

您可以使其可复制(例如,通过将其状态存储在 std::shared_ptr 中),或编写仅移动的 std::function

#include <utility>
#include <memory>

template<class Sig>class func;
namespace details{
  template<class Sig>struct inner;
  template<class R,class...Args>
  struct inner<R(Args...)>{
    virtual ~inner() {};
    virtual R invoke(Args&&...args) =0;
  };
  template<class F,class Sig>struct impl;
  template<class F,class R,class...Args>
  struct impl<F,R(Args...)>:inner<R(Args...)>{
    F f;
    template<class... Ts>
    impl(Ts&&...ts):f(std::forward<Ts>(ts)...){}
    R invoke(Args&&...args)override{
      return f(std::forward<Args>(args)...);
    }
  };
}
template<class T>struct emplace_as{};
template<class R,class...Args>
class func<R(Args...)>{
  std::unique_ptr<details::inner<R(Args...)>> pImpl;
public:
  R operator()(Args...args){
    return pImpl->invoke(std::forward<Args>(args)...);
  }
  explicit operator bool()const{return pImpl;}
  func(func&&)=default;
  template<class F,class...Ts,class=typename std::enable_if<
    std::is_convertible<decltype(std::declval<F>()(std::declval<Args>()...)),R>::value
  >::type>
  func(emplace_as<F>,Ts&&...ts):
    pImpl( new details::impl<F, R(Args...)>{std::forward<Ts>(ts)...} )
  {}

  template<class F,class=typename std::enable_if<
    std::is_convertible<decltype(std::declval<F>()(std::declval<Args>()...)),R>::value
  >::type>
  func(F&&f):
    func(
      emplace_as<typename std::decay<F>::type>(),
      std::forward<F>(f)
    )
  {}
};

something like that

(需要添加的特性:在() 上重载的右值引用,可能是swap,可能是assignemplace,可能是result_type 的类型定义等),可能是target 和@987654334 @)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-08-28
    • 2014-06-18
    • 2017-09-23
    • 1970-01-01
    • 2020-11-07
    • 2014-09-09
    相关资源
    最近更新 更多