是否在std::Function返回类型定义中使用[[nodisard]]?

2022-08-10 00:00:00 c++ c++17 std nodiscard

我想知道有没有这样的方法:

using CallbackType = std::function<[[nodiscard]]bool(void)>; 

(我知道上面的代码无法编译,并抱怨nodiscard无法应用于类型!)

我的目标是强制回调的调用方检查它的返回值!


解决方案

您可以直接包装std::function或真正的lambda来修改属性,如[[nodiscard]]

您关于公共继承有问题的评论是完全正确的。但是,这不适用于私有继承,因为您可以控制这些问题。
编辑:但如果您绝对不喜欢它,您可以重写下面的代码,以使用私有成员而不是私有继承,代价是使代码更冗长,但好处是支持原始函数指针。

template <typename Function>
struct NoDiscard : private Function {
  NoDiscard() = default;
  NoDiscard(NoDiscard const&) = default;
  NoDiscard(NoDiscard&&) = default;
  NoDiscard& operator=(NoDiscard const&) = default;
  NoDiscard& operator=(NoDiscard&&) = default;

  NoDiscard(Function&& fn) : Function(std::move(fn)) {}
  NoDiscard(Function const& fn) : Function(fn) {}

  template <typename... Ts>
  [[nodiscard]] auto operator()(Ts&&... ts) {
    return Function::operator()(std::forward<Ts>(ts)...);
  }
};

// convenience function to make the call look intuitive
template <typename Function>
auto add_nodiscard(Function&& f) {
  return NoDiscard<Function>(std::forward<Function>(f));
}
这将允许您简单地add_nodiscard到任何函数器或可调用类型。示例:

void test_good(auto fn) {
  (void)fn();
}
void test_bad(auto fn) {
  fn();
}


int main() {
  test_good(             (                         ([](){return true;})));
  test_bad (             (                         ([](){return true;})));
  test_good(add_nodiscard(                         ([](){return true;})));
  test_bad (add_nodiscard(                         ([](){return true;}))); // warns about discarded result

  test_good(             (std::function<bool(void)>([](){return true;})));
  test_bad (             (std::function<bool(void)>([](){return true;})));
  test_good(add_nodiscard(std::function<bool(void)>([](){return true;})));
  test_bad (add_nodiscard(std::function<bool(void)>([](){return true;}))); // warns about discarded result
}

live demo

这有一个警告,不能将其与必须接收std::function对象的类型一起使用。

我认为这样的目标是不可能的,因为您不能更改库函数的类型或直接向其添加属性。并且您在std::function调用之前添加的任何包装都不会对[[nodiscard]]产生影响,因为std::function将尽职尽责地从其被调用者返回返回值。

免责声明:我是说,这是绝对不可能的,唯一的目的是被证明是错误的。

相关文章