В чем разница между встроенной и неконтролируемой лямбда-захватом в заголовке?
Если я объявляю лямбда без захвата в заголовке, в чем разница между
inline auto myLambda = []() { ... };
а также
constexpr auto myLambda = []() { ... };
Если я правильно понимаю, constexpr
подразумевает inline, а лямбды по умолчанию являются constexpr. Так что я даже не уверен, что мне нужно ключевое слово inline
или constexpr
.
Чего я хочу избежать, объявляя myLambda
inline, так это нарушения One Definition Rule (ODR), так как эта переменная будет видна в нескольких единицах перевода.
Если я правильно понимаю,
constexpr
подразумевает inline, а лямбды по умолчанию являютсяconstexpr
.
Первая часть верна, но не для этого случая. Из [dcl.constexpr]/1:
Функция или член статических данных, объявленные с помощью
constexpr
илиconsteval
неявно являются встроенной функцией или переменной ([dcl.inline]).
В нашем случае у нас нет ни функции, ни статического члена данных, поэтому он не является встроенным. Вы должны явно пометить его как таковой.
Вторая часть не совсем правильная. Из [expr.prim.lambda.closure]/4:
Оператор вызова функции или любая конкретная специализация шаблона оператора является функцией constexpr, если за соответствующим предложением-объявлением параметра-лямбда-выражения следует
constexpr
илиconsteval
, или он удовлетворяет требованиям для функции constexpr ([dcl.constexpr]).
Оператор constexpr
по умолчанию является constexpr
, а сама лямбда - нет. Что для лямбды без захвата в основном хорошо, вы все равно можете использовать оператор вызова - как показано в примере для этого раздела:
auto ID = [](auto a) { return a; };
static_assert(ID(3) == 3); // OK
Короче говоря, если вы объявляете эту лямбду в заголовке, вам определенно нужно ключевое слово inline
и вам не помешает просто constexpr
ключевому слову constexpr
.