在 MSVC19 中的 lambda 中捕获可变参数包的问题

Issue with capturing of a variadic pack inside of lambda in MSVC19

我正在尝试编写一个 SFINAE 友好的 bind_back 函数,类似于 C++20 的 std::bind_front。但是,MSVC 的代码似乎存在一些问题。

我设法将问题最小化为以下代码片段:

auto bind_back(auto f, auto ...back_args) {
    return [=](auto ...front_args)
        requires requires { f(front_args..., back_args...); } {
            return f(front_args..., back_args...);
    };
}

int main() {
    auto h = bind_back([]{});
    h();
}

https://godbolt.org/z/3bc8GaqTv

编译此片段时,出现以下错误:

<source>(10): error C2672: 'operator __surrogate_func': no matching overloaded function found
<source>(10): error C2893: Failed to specialize function template 'decltype(auto) bind_back::<lambda_1>::operator ()(_T1...) const'
<source>(5): note: see declaration of 'bind_back::<lambda_1>::operator ()'
<source>(10): note: With the following template arguments:
<source>(10): note: '_T1={}'

看来Clang和GCC编译这段代码都没有问题

我的问题是:

  1. 这是有效的 C++20,对吧?
  2. 是否有针对 MSVC 的解决方法,以便我可以使用这些类型的构造? (即使其对 SFINAE 友好)。
  1. this is valid C++20, right?

是的,在 C++20 中 lambda 可以被 requires 子句约束,所以它是 well-formed。

  1. is there a work around for MSVC such that I can use these kind of constructs? (i.e. making it SFINAE-friendly).

MSVC 似乎在处理 requires 子句方面存在一些问题。相反,您可以使用 std::invocable:

#include <concepts>

template<class F, class... BoundArgs>
auto bind_back(F f, BoundArgs... bound_args) {
  return [=]<class... CallArgs>(CallArgs... call_args)
    requires std::invocable<F&, CallArgs&..., BoundArgs&...> {
      return f(call_args..., bound_args...);
  };
}

Demo.

值得注意的是,P2387 还引入了 std::bind_back 以支持 user-defined 作用域适配器的管道运算符。