Home > front end >  What is the difference between captures and parameters in a C laambda expression?
What is the difference between captures and parameters in a C laambda expression?

Time:03-25

https://en.cppreference.com/w/cpp/algorithm/sort

  std::array<int, 10> s = {5, 7, 4, 2, 8, 6, 1, 9, 0, 3};
 
    auto print = [&s](std::string_view const rem) {
        for (auto a : s) {
            std::cout << a << ' ';
        }
        std::cout << ": " << rem << '\n';
    };
 
    std::sort(s.begin(), s.end());
    print("sorted with the default operator<");
 

For example, in this code, why is the capture "s" and the parameter "sorted with the default operator<"? Why is the capture "sorted with the default operator<" and not the parameter "s"?

CodePudding user response:

A lambda isn't a function its a class with an operator() that takes your parameters as arguments. So the caputured variables will become members of the class and thus will be reusable and the parameters will be the arguments of the operator.

CodePudding user response:

The captured values stay with the lambda object while the function arguments exist only for the call. As with any function you can call the lambda function several times, each with a different argument list to its parameter list. The lambda object, however, is constructed exactly once, at which point the captures are bound to the internal members of the lambda.

If you throw your code into https://cppinsights.io, you get an idea of what the compiler does with your lambda function:

  std::array<int, 10> s = {{5, 7, 4, 2, 8, 6, 1, 9, 0, 3}};
    
  class __lambda_7_18
  {
    public: 
    inline /*constexpr */ void operator()(const std::basic_string_view<char, std::char_traits<char> > rem) const
    {
      {
        std::array<int, 10> & __range1 = s;
        int * __begin1 = __range1.begin();
        int * __end1 = __range1.end();
        for(; __begin1 != __end1;   __begin1) {
          int a = *__begin1;
          std::operator<<(std::cout.operator<<(a), ' ');
        }
        
      }
      std::operator<<(std::operator<<(std::operator<<(std::cout, ": "), std::basic_string_view<char, std::char_traits<char> >(rem)), '\n');
    }
    
    private: 
    std::array<int, 10> & s;
    
    public:
    __lambda_7_18(std::array<int, 10> & _s)
    : s{_s}
    {}
    
  };
  
  __lambda_7_18 print = __lambda_7_18{s};
  print.operator()(std::basic_string_view<char, std::char_traits<char> >("sorted with the default operator<"));

As you can see, your print lambda is an object that holds a reference to the captured array: s. When you call it, its operator() member function is invoked with the arguments you pass to it, here an std::string_view with the value "sorted with the default operator<". You'd be free to call it again with a different value.

  • Related