c++lambdac++17constexpr

Why can a lambda passed as an argument be used in a constant expression?


Why does this code compile?

template<typename Callable>
int foo(Callable callable)
{
     static_assert(callable());
      return 0;
}

static const auto r = foo([] { return true; });

Compiler Explorer example

Shouldn't it be illegal to use a function parameter in a constant expression (the static_assert)?

It's disallowed for structural types, but it seems OK for lambdas as soon as they are passed by value. All of gcc, clang, and msvc accept it, so it might be legal somehow. I just can't find any reference why it's valid.


Solution

  • While the variable is not a constant and not usable itself in a constant expression, members of the variable can be constant expressions. In this case the operator() of the lambda object is marked as constexpr, and it doesn't depend on the lambda object, so it can be used even though the object isn't.

    We can get a little more of a simplified example with

    int main()
    {
        std::array<int, 4> nums{1, 3, 5, 7};
    
        static_assert(nums.size() == 4);
    }
    

    Here nums is not a constant, but size() always is as it's marked constexpr, and it just returns N, so it is still usable.