c++lambdastandardsmember-functionsconst-correctness

Why can a const object call a non-const member function?


Consider the following code:

int main() {
    auto const fn = [] mutable {};
    fn(); // ok, why?
}

As per the latest C++ standard draft [expr.prim.lambda.closure] 7.5.6.2/6 (emphasis mine):

The function call operator or operator template is a static member function or static member function template (11.4.9.2) if the lambda-expression’s parameter-declaration-clause is followed by static. Otherwise, it is a non-static member function or member function template (11.4.3) that is declared const (11.4.3) if and only if the lambda-expression’s parameter-declaration-clause is not followed by mutable and the lambda declarator does not contain an explicit object parameter.

Since the lambda is marked as mutable, then:

However, both gcc & clang accept the code above, see https://godbolt.org/z/5Gohefz7o

Why can a const object call a non-const member function?


Solution

  • CppInsights might help to understand Demo:

    class __lambda_2_21
    {
      public: 
      inline /*constexpr */ void operator()() {}
      
      using retType_2_21 = void (*)();
      inline constexpr operator retType_2_21 () const noexcept
      {
        return __invoke;
      }
      
      private: 
      static inline /*constexpr */ void __invoke()
      {
        __lambda_2_21{}.operator()();
      }
    };
      
    const __lambda_2_21 fn = __lambda_2_21{};
    fn.operator __lambda_2_21::retType_2_21()();
    

    You don't call the non-const operator(), but as the lambda is capture-less, you call the function pointer (provided with conversion operator).