This code compiles fine in g++ (coliru), but not MSVC (godbolt and my VS2017).
#include <type_traits>
#include <iostream>
template<class T> void f(){
constexpr bool b=std::is_same_v<T,int>; //#1
auto func_x=[&](){
if constexpr(b){ //#error
}else{
}
};
func_x();
}
int main(){
f<int>();
}
(6): error C2131: expression did not evaluate to a constant
(6): note: failure was caused by a read of a variable outside its lifetime
(6): note: see usage of 'this'
Which one (g++ or MSVC) is wrong?
What is this
in "see usage of 'this'"??
How to work around it while keep the compile-time guarantee?
In my real case, b (#1)
is a complex statement depends on a few other constexpr variables.
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.
The alternatives don't have the all of the positives of static constexpr - you're guaranteed compile time processing, type safety, and (potentially) lower usage of memory (constexpr variables don't need to take up memory, they are effectively hard coded unless if possible).
A static constexpr variable has to be set at compilation, because its lifetime is the the whole program. Without the static keyword, the compiler isn't bound to set the value at compilation, and could decide to set it later. So, what does constexpr mean?
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.
Gcc is right. b
(as constexpr
variable) doesn't need to be captured in fact.
A lambda expression can read the value of a variable without capturing it if the variable
- is constexpr and has no mutable members.
GCC LIVE
It seems if making b
static
then MSVC could access b
without capturing.
template<class T> void f(){
constexpr static bool b=std::is_same_v<T,int>;
auto func_x=[](){
if constexpr(b){
}else{
}
};
func_x();
}
MSVC LIVE
And
How to work around it while keep the compile-time guarantee?
We can't keep the constexpr-ness for the captured variables. They become non-static data members of the lambda closure type and non-static data members can't be constexpr
.
How to work around it while keep the compile-time guarantee?
Marking the constexpr bool
as static
serves as a work around.
See Demo
Alternately, you can use the condition in the if constexpr
instead of assigning it to a bool
. Like below:
if constexpr(std::is_same_v<T,int>)
See Demo
Note that there have been bugs raised for MSVC regarding constexpr
with respect to lambda expressions.
One such is: problems with capturing constexpr in lambda
and another is: if constexpr in lambda
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With