为什么 std::apply 函数模板失败,但带有显式模板参数列表的 lambda 表达式却没有?

Why does std::apply fail with function template, but not with a lambda expression with explicit template parameter list?

在查看来自 cpprefrence 的 std::apply 引用时,我们可以看到函数模板不能作为 std::apply 的可调用对象传递。让我们考虑以下函数模板:

template<typename T>
T add_generic(T first, T second) { return first + second; }

所以在std::apply调用中无法推导出函数模板,所以不能使用下面的代码:

std::apply(add_generic, std::make_pair(2.0f, 3.0f)); // Error: can't deduce the function type

请注意,这与 不是同一个问题。在那个答案中,作者写了一个没有显式模板参数的 lambda 表达式。

std::cout << std::apply(
    [](auto first, auto second) { return add_generic(first, second); },
    std::make_tuple(2.0f,3.0f)) << '\n';

但是正如您在 c++20 中所了解的那样,您可以使用带有显式模板参数列表的 lambda 表达式。所以我尝试了这个功能,令人惊讶的是编译器没有引发任何错误。

std::apply([]<typename T>(T first,T second){
    return first+second;
},std::make_pair(2.0,3.0));

为什么编译器能够在最后一种情况下推断出类型?两者有什么区别吗?

函数 模板 不是函数,就像饼干切割器不是饼干一样。 C++ 模板为每组模板参数创建新函数。这就是为什么 add_generic 不是一个可行的论点。它不是函数,不能作为值传递。要获得函数,编译器需要推导模板参数。但它只能在 apply 传递可调用函数之后执行此操作。鸡和蛋就在那里。

为什么 lambda 有效?因为它也不是一个简单的函数。它产生一个隐藏的对象类型

struct __lambda_at_line_N {
  template<typename T>
  auto operator()(T first, T second) { /* ... */ }
};

并通过that

std::apply(__lambda_at_line_N{},std::make_pair(2.0,3.0));

这是一个实际的对象,一个值。它的类型不依赖于需要在 std::apply 内部发生以调用 operator() 的模板参数推导。这就是它起作用的原因。