This code compiles fine in gcc, but fail in Visual C++.
MCVE = https://godbolt.org/z/K7d5PEs65
int main(){
int localVariable=0; //some local variable
auto lamb=[&]<int s>() {
if constexpr(s==5){localVariable=7;}
///^ may modify some local variables
return 8;
};
constexpr int gOk=lamb.operator()<2>();
[&]<int s2>() {
///vvv can edit only here
constexpr int gFail=lamb.operator()<s2>();
///^^^ can edit only here
}.operator()<2>();
}
Error C2131 expression did not evaluate to a constant
I need gFail
to be a constexpr
variable, while lamb
sometimes create run-time side effect, depending on the value of template variable s
.
Please give reference and workaround for Visual C++ case.
Edit: By the way, the reason that I mix between constexpr and non-constexpr inside the same lamb
is to make calling convenient. By design, in user mind, he must know in advance that the instance of function lamb
is constexpr or not.
I believe the problem you experience it is a bug/deficiency of MSVC, but I would let language lawyers provide the exact reasons (or refutation of my statement).
Typically what I do in these situations is to pack the constexpr
value inside an integral constant. This is something MSVC can chew:
#include <iostream>
#include <cstdlib>
int main(){
int localVariable=0; //some local variable
auto lamb=[&]<int s>() {
if constexpr(s==5){localVariable=7;}
return std::integral_constant<int, 8>{};
};
constexpr int gOk=lamb.operator()<2>().value;
[&]<int s2>() {
auto tmp = lamb.operator()<s2>();
constexpr int gFail=tmp; //tmp implicitly casted from integral_constant to int.
}.operator()<2>();
}
tmp
needs to be explicitly spelled out for MSVC. If you assign directly to gFail
you get the same "not evaluate to a constant".
Unfortunately this does not follow your "can edit only here" guide.
Update: I am concerned that what you do won't actually work in any compiler. If you try using 5
as a template argument, you do actually get an error in all three compilers:
#include <iostream>
#include <cstdlib>
int main(){
int localVariable=0; //some local variable
auto lamb=[&]<int s>() {
if constexpr(s==5){localVariable=7;} //error
///^ may modify some local variables
return 8;
};
constexpr int gOk=lamb.operator()<5>();
std::cout << localVariable;
}
gcc gives:
<source>: In function 'int main()':
<source>:12:43: in 'constexpr' expansion of 'lamb.main()::<lambda()>()'
<source>:8:43: error: the value of 'lamb' is not usable in a constant expression
8 | if constexpr(s==5){localVariable=7;}
| ~~~~~~~~~~~~~^~
<source>:7:12: note: 'lamb' was not declared 'constexpr'
7 | auto lamb=[&]<int s>() {
| ^~~~
Compiler returned: 1