I'm trying to use std::size
instead of macros like _countof
or ARRAYSIZE
, but I'm running into scoping problems.
Is the following code legal?
#include <iterator>
int main()
{
int arr1[4];
auto f = [](int(&arr2)[std::size(arr1)])
{
arr2[0] = 1;
};
(void)arr1;
(void)f;
}
GCC and MSVC compile it fine, but Clang complains:
error: variable 'arr1' cannot be implicitly captured in a lambda with no capture-default specified
auto f = [](int(&arr2)[std::size(arr1)])
Which one is correct?
I think Clang is correct.
(Using terminology from the current C++23 draft.)
std::size(arr1)
is not part of an unevaluated operand, so the expression arr1
is a potentially-evaluated id-expression naming the variable arr1
. The expression is also not part of a discarded-value expression, nor is the variable arr1
usable in constant expressions. Therefore the expression odr-uses arr1
. (The variable could be made usable in constant expressions, making arr1
not an odr-use, by adding constexpr
on it.)
However, being a variable with automatic storage duration, arr1
is a local entity that is not odr-usable in the scope in which the expression appears. Specifically, to be odr-usable inside a lambda a local entity must be captured by the lambda, which arr1
is not. Even with a capture however, CWG 2380 clarifies that the local entity is odr-usable only in the block scope of the lambda, not in the function parameter declaration clause.
A program that odr-uses a local enitity in a scope in which it isn't odr-usable is ill-formed.