首页 > 解决方案 > std::invoke - 完美的转发函子

问题描述

试图理解为什么以下示例无法编译:

#include <functional>

template <typename F>
void f1(F&& f)
{
  std::forward<F>(f)("hi");
}

template <typename F>
void f2(F&& f)
{
  std::invoke(f, "hi");  // works but can't perfect forward functor
}

template <typename F>
void f3(F&& f)
{
  std::invoke<F>(f, "hi");
}

int main()
{
  f1([](const char*) {});  // ok
  f2([](const char*) {});  // ok
  f3([](const char*) {});  // error
}

cppreference说了以下关于std::invoke

  1. f使用参数 args调用 Callable 对象。正如INVOKE(std::forward<F>(f), std::forward<Args>(args)...). std::is_invocable_v<F, Args...>此重载仅在为真时才参与重载决议。

那么为什么f3不等于f1呢?

标签: c++c++17

解决方案


std::invoke本身就是一个函数。在您的情况下,它的第一个参数是右值引用,f而是左值,因此会发生错误。

INVOKE(std::forward<F>(f), std::forward<Args>(args)...)std::invoke在正确选择和调用函数后执行。基本上,您的 lambda 函数按如下方式传递:

original lambda in main -> the parameter of f3 -> the parameter of std::invoke -> the parameter of INVOKE

所以std::forwardINVOKE(std::forward<F>(f), std::forward<Args>(args)...)最后一步使用了in,而中步需要转发lambda(的参数f3-> 的参数std::invoke)。我想这就是你的困惑所在。


推荐阅读