Search code examples
c++visual-c++variadic-templatesc++20sfinae

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


I'm trying to write a SFINAE-friendly bind_back function, similar to C++20's std::bind_front. However, it seems that MSVC is having some issues with the code.

I managed to minimize the issue to the following code fragment:

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

While compiling this fragment, I get the following error:

<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={}'

It seems that both Clang and GCC have no problems compiling this code.

My questions are:

  1. this is valid C++20, right?
  2. is there a work around for MSVC such that I can use these kind of constructs? (i.e. making it SFINAE-friendly).

Solution

    1. this is valid C++20, right?

    Yes, lambdas can be constrained by requires clause in C++20, so it's 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 seems to have some issues with handling requires clause. Instead, you can use 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.

    It is worth noting that P2387 also introduced std::bind_back to support pipe operator for user-defined scope adapters.