创建一个带有任何签名的 "do-nothing" `std::function`?

Create a "do-nothing" `std::function` with any signature?

我想创建一个带有任意签名的简单无操作 std::function 对象。为此,我创建了两个函数:

template <typename RESULT, typename... ArgsProto>
  std::function<RESULT(ArgsProto...)> GetFuncNoOp()
  {
    // The "default-initialize-and-return" lambda
    return [](ArgsProto...)->RESULT { return {}; };
  }

template <typename... ArgsProto>
  std::function<void(ArgsProto...)> GetFuncNoOp()
  {
    // The "do-nothing" lambda
    return [](ArgsProto...)->void {};
  }

其中每一个都运行良好(很明显,第一个版本可能会在 RESULT 对象中创建未初始化的数据成员,但在实践中我认为这不是什么大问题)。但是第二个,void-返回版本是必要的,因为 return {}; never returns void (这将是一个编译错误),并且它不能写成第一个的模板特化,因为初始签名是可变的。

所以我不得不在这两个功能之间做出选择,只实现一个,或者给它们不同的名称。但是我 真正 想要的只是轻松地初始化 std::function 对象,这样在调用时它们什么都不做而不是抛出异常。这可能吗?

注意 the default constructor of std::function does not do what I want.

你戴牙套太执着了

template <typename RESULT, typename... ArgsProto>
std::function<RESULT(ArgsProto...)> GetFuncNoOp()
{
  // && avoids unnecessary copying. Thanks @Yakk
  return [](ArgsProto&&...) { return RESULT(); }; 
}
template <class T> struct dummy {
  static auto get() -> T { return {}; }
};
template <> struct dummy<void> {
  static auto get() -> void {}
};

template <typename RESULT, typename... ArgsProto>
std::function<RESULT(ArgsProto...)> GetFuncNoOp()
{
  return [](ArgsProto...)->RESULT { return dummy<RESULT>::get(); };
}

但是...@T.C。解决方案要优雅得多。只是想展示另一种方法,它可以应用于任何你需要专注于某事的地方。"part"。

我不喜欢必须指定签名。

假设您有一个 std::function 实现,其中 std::function<void()> 可以接受类型 int(*)() 的函数指针,这是一个非类型擦除的 noop 对象投射到任何 std::function:

struct noop {
  struct anything {
    template<class T>
    operator T(){ return {}; }
    // optional reference support.  Somewhat evil.
    template<class T>
    operator T&()const{ static T t{}; return t; }
  };
  template<class...Args>
  anything operator()(Args&&...)const{return {};}
};

如果您的 std::function 不支持该转换,我们添加:

  template<class...Args>
  operator std::function<void(Args...)>() {
    return [](auto&&...){};
  }

假设您的 std::function 是 SFINAE 友好的,这应该可以处理这种情况。

live example.

要使用,只需使用noop{}。如果你真的需要一个返回 noop 的函数,请执行 inline noop GetFuncNoop(){ return{}; }.

这样做的一个附带好处是,如果您将 noop 传递给非类型擦除操作,我们就不会因为什么都不做而得到毫无意义的 std::function 开销。

引用支持是邪恶的,因为它创建了一个全局对象并在所有地方传播对它的引用。如果一个 std::function<std::string&()> 被调用,并且结果 string 被修改,修改后的字符串将在所有地方使用(并且在使用之间没有任何同步)。加上不告诉任何人分配全球资源似乎很粗鲁。

我只是 =delete operator T& 情况,并生成编译时错误。