Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can I use a constexpr value in a lambda without capturing it?

I would want to use a constexpr value in a lambda. Reading the answer to Using lambda captured constexpr value as an array dimension, I assumed the following should work:

  #include<array>   int main()   {      constexpr int i = 0;     auto f = []{         std::array<int, i> a;     };     return 0;   } 

However, Clang 3.8 (with std=c++14) complains that

variable 'i' cannot be implicitly captured in a lambda with no capture-default specified

Should this be considered a bug in clang 3.8?

BTW:

The above code does compile with gcc 4.9.2. If I change the lambda expresion to capture explicitly:

... auto f = [i]{ ... 

clang 3.8 compiles it, but gcc 4.9.2 fails:

error: the value of ‘i’ is not usable in a constant expression ...

like image 829
Olaf Booij Avatar asked Nov 23 '15 14:11

Olaf Booij


People also ask

Can Lambda be constexpr?

Visual Studio 2017 version 15.3 and later (available in /std:c++17 mode and later): A lambda expression may be declared as constexpr or used in a constant expression when the initialization of each data member that it captures or introduces is allowed within a constant expression.

Does Lambda capture reference by value?

The mutable keyword is used so that the body of the lambda expression can modify its copies of the external variables x and y , which the lambda expression captures by value. Because the lambda expression captures the original variables x and y by value, their values remain 1 after the lambda executes.

What is a constexpr variable?

constexpr indicates that the value, or return value, is constant and, where possible, is computed at compile time. A constexpr integral value can be used wherever a const integer is required, such as in template arguments and array declarations.

What does it mean to Lambda capture this?

The lambda is capturing an outside variable. A lambda is a syntax for creating a class. Capturing a variable means that variable is passed to the constructor for that class. A lambda can specify whether it's passed by reference or by value.


1 Answers

Should this be considered a bug in clang 3.8?

Yep. A capture is only needed if [expr.prim.lambda]/12 mandates so:

enter image description here

Note in particular the highlighted example. f(x) does not necessitate x to be captured, because it isn't odr-used (overload resolution selects the overload with the object parameter). The same argumentation applies to your code - [basic.def.odr]/3:

A variable x whose name appears as a potentially-evaluated expression ex is odr-used by ex unless applying the lvalue-to-rvalue conversion (4.1) to x yields a constant expression (5.20) that does not invoke any non-trivial functions…

This requirement is certainly met.

…and, if x is an object, ex is an element of the set of potential results of an expression e, where either the lvalue-to-rvalue conversion (4.1) is applied to e, or e is a discarded-value expression (Clause 5).

i is its set of potential results as per [basic.def.odr]/(2.1), and the l-t-r conversion is indeed immediately applied as its passed to a non-type template parameter of object type.

Hence, as we have shown that (12.1) isn't applicable - and (12.2) clearly isn't, either - Clang is wrong in rejecting your snippet.

like image 187
Columbo Avatar answered Oct 11 '22 12:10

Columbo