Lambda failed to capture array element

The following C ++ code makes the GCC (6.3.0) and Clang (3.8.0) compiler insane.

for (auto v : vectors2d)
    for_each (begin(ret), end(ret), [v[3]] (int &n) { n+= v[3];});

      

While the following is fine [/ p>

for (auto v : vectors2d) {
    auto val = v[3];
    for_each (begin(ret), end(ret), [val] (int &n) { n+= val;});
}

      

I know in C ++ 14 I can do something like

for (auto v : vectors2d)
    for_each (begin(ret), end(ret), [val=v[3]] (int &n) { n+= val;});

      

GCC bug

expected identifier before '[' token

      

Klang says

expected ',' or ']' in lambda capture list

      

My question is, why is it illegal to [v[3]]

appear on the capture list?

+3


source to share


2 answers


My question is why is it banned for [v[3]]

in the capture list?

As described in 5.1.2 / 1 [expr.prim.lambda] in N4141, the items in the capture list must be either a simple capture or init-capture.

The first is any of



  • identifier
  • &

    identifier
  • this

    ,

the latter is either an identifier initializer or an identifier initializer &

.

v[3]

does not match any of the above and is thus correctly rejected by the compiler.

+7


source


v[3]

is not a variable - it is a complex expression that expands to *(v + 3)

(unless operator[]

overloaded). Thus, capture is v[3]

very similar in meaning to capture x * x + y * y

- and it makes much less meaning. For example. the compiler must accept a x * x + y * y

lambda inside, but sometimes reject y * y + x * x

, because the overloaded operators are not supposed to be commutative.

Basically, you are asking the compiler, "if I use an expression equivalent to what I captured, that's fine, but if I mix the variables the other way around, you should give me a compiler error."

Suppose it v[3]

is legal. Then all of the following lambdas must compile correctly:



[v[3]]() { return v[3]; }
[v[3]]() { return v[2 * 2 - 1]; }
[v[3]](int x) { assert(x == 3); return v[x]; }

      

So, if we want the "invalid capture" to be a compiler error, the compiler must somehow "prove" that we will not access any element in v

except v[3]

. This is more difficult than the halting problem, so it is not possible.

We could, of course, make some less stringent restrictions: for example, allow only v[3]

but not, v[2 * 2 - 1]

or create some algorithm to detect such cases that work "well enough" but sometimes provide false negatives. I don't think it's worth the effort - you can always "cache" an expression inside a variable and capture it by value.

+3


source







All Articles