Home > OS >  What will happen if I pass a mutable lambda to a function as const reference?
What will happen if I pass a mutable lambda to a function as const reference?

Time:05-12

What does the code actually do when I pass a mutable lambda as const reference?

Why does not the compiler raise error, is this an undefined operation?

Why f1 and f2 are differnt which f1 uses std::function<void()> and f2 uses auto?

I found a similar question but I still don't fully understand

A const std::function wraps a non-const operator() / mutable lambda

#include <iostream>
#include <functional>

void call(std::function<void()> const & cb) {
    cb();
    cb();
}

int main() {
    std::function<void()> f1 = [a = 0] () mutable {
        std::cout <<   a << std::endl;
    };
    call(f1); // prints 1 2
    call(f1); // prints 3 4

    auto f2 = [a = 0] () mutable {
        std::cout <<   a << std::endl;
    };
    call(f2); // prints 1 2
    call(f2); // prints 1 2
}

https://godbolt.org/z/765endY7c

CodePudding user response:

In first case both calls of call(f1) are using same instance of std::function<void()>.

In second case call(f2); implicit conversion form lambda to std::function<void()> kicks in and respective temporary object is created. So second call uses new copy of temporary object.

Try transform this code in cppinsights to see this with more details.

int main()
{
    
  class __lambda_10_32
  {
    public: 
    inline /*constexpr */ void operator()()
    {
      std::cout.operator<<(  a).operator<<(std::endl);
    }
    
    private: 
    int a;
    public: 
    // inline /*constexpr */ __lambda_10_32(const __lambda_10_32 &) noexcept = default;
    // inline /*constexpr */ __lambda_10_32(__lambda_10_32 &&) noexcept = default;
    __lambda_10_32(const int & _a)
    : a{_a}
    {}
    
  };
  
  std::function<void ()> f1 = std::function<void ()>(__lambda_10_32{0});
  call(f1);
  call(f1);
    
  class __lambda_16_15
  {
    public: 
    inline /*constexpr */ void operator()()
    {
      std::cout.operator<<(  a).operator<<(std::endl);
    }
    
    private: 
    int a;
    public: 
    // inline /*constexpr */ __lambda_16_15(const __lambda_16_15 &) noexcept = default;
    // inline /*constexpr */ __lambda_16_15(__lambda_16_15 &&) noexcept = default;
    __lambda_16_15(const int & _a)
    : a{_a}
    {}
    
  };
  
  __lambda_16_15 f2 = __lambda_16_15{0};
  call(std::function<void ()>(__lambda_16_15(f2)));
  call(std::function<void ()>(__lambda_16_15(f2)));
  return 0;
}
  • Related