Search code examples
c++lambdac++17inlineconstexpr

What is the difference between inline and constexpr captureless lambda in a header?


If I declare a captureless lambda in a header, what is the difference between

inline auto myLambda = []() { ... };

and

constexpr auto myLambda = []() { ... };

If I understand correctly, constexpr imply inline, and lambdas are constexpr by default. So I'm not even sure that I need the inline or constexpr keyword.

What I want to avoid by declaring myLambda inline is One Definition Rule (ODR) violations, since this variable with be visible in multiple translation units.


Solution

  • If I understand correctly, constexpr imply inline, and lambdas are constexpr by default.

    The first part is true, but not for this case. From [dcl.constexpr]/1:

    A function or static data member declared with the constexpr or consteval specifier is implicitly an inline function or variable ([dcl.inline]).

    In our case, we don't have either a function or a static data member, so it's not implicitly inline. You'd have to explicitly mark it as such.

    The second part isn't quite right. From [expr.prim.lambda.closure]/4:

    The function call operator or any given operator template specialization is a constexpr function if either the corresponding lambda-expression's parameter-declaration-clause is followed by constexpr or consteval, or it satisfies the requirements for a constexpr function ([dcl.constexpr]).

    The call operator is constexpr by default, but the lambda itself is not. Which for a capture-less lambda is basically fine, you can still use the call operator - as demonstrated in the example for this section:

    auto ID = [](auto a) { return a; };
    static_assert(ID(3) == 3);                      // OK
    

    In short, if you're declaring this lambda in the header, you definitely need the inline keyword and it doesn't hurt to just slap on the constexpr keyword either.