Search code examples
c++lambdalanguage-lawyerc++17if-constexpr

Constexpr variable captured inside lambda loses its constexpr-ness


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.


Solution

  • 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.