Constexpr variable captured inside lambda loses its constexpr-ness












17















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.










share|improve this question

























  • Coliru uses GCC 8.2; GCC 8.3 from gcc.godbolt.org also rejects the code. Clang 7.0.0 compiles it.

    – HolyBlackCat
    19 hours ago
















17















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.










share|improve this question

























  • Coliru uses GCC 8.2; GCC 8.3 from gcc.godbolt.org also rejects the code. Clang 7.0.0 compiles it.

    – HolyBlackCat
    19 hours ago














17












17








17








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.










share|improve this question
















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.







c++ lambda language-lawyer c++17 if-constexpr






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited 19 hours ago









HolyBlackCat

16.8k33468




16.8k33468










asked 19 hours ago









javaLoverjavaLover

2,7821939




2,7821939













  • Coliru uses GCC 8.2; GCC 8.3 from gcc.godbolt.org also rejects the code. Clang 7.0.0 compiles it.

    – HolyBlackCat
    19 hours ago



















  • Coliru uses GCC 8.2; GCC 8.3 from gcc.godbolt.org also rejects the code. Clang 7.0.0 compiles it.

    – HolyBlackCat
    19 hours ago

















Coliru uses GCC 8.2; GCC 8.3 from gcc.godbolt.org also rejects the code. Clang 7.0.0 compiles it.

– HolyBlackCat
19 hours ago





Coliru uses GCC 8.2; GCC 8.3 from gcc.godbolt.org also rejects the code. Clang 7.0.0 compiles it.

– HolyBlackCat
19 hours ago












2 Answers
2






active

oldest

votes


















14














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.






share|improve this answer


























  • Is there a location in the C++ standard where this is stated?

    – Nicol Bolas
    12 hours ago











  • Indeed, C++17 seems to directly contradict this. b is implicitly captured by the lambda; there is no caveat about being a constant expression.

    – Nicol Bolas
    12 hours ago








  • 3





    @NicolBolas since b is constexpr, performing an lvalue-to-rvalue conversion on it directly does not constitute an odr-use. See [basic.def.odr]/3 for the standard reference.

    – Brian
    11 hours ago



















7















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






share|improve this answer

























    Your Answer






    StackExchange.ifUsing("editor", function () {
    StackExchange.using("externalEditor", function () {
    StackExchange.using("snippets", function () {
    StackExchange.snippets.init();
    });
    });
    }, "code-snippets");

    StackExchange.ready(function() {
    var channelOptions = {
    tags: "".split(" "),
    id: "1"
    };
    initTagRenderer("".split(" "), "".split(" "), channelOptions);

    StackExchange.using("externalEditor", function() {
    // Have to fire editor after snippets, if snippets enabled
    if (StackExchange.settings.snippets.snippetsEnabled) {
    StackExchange.using("snippets", function() {
    createEditor();
    });
    }
    else {
    createEditor();
    }
    });

    function createEditor() {
    StackExchange.prepareEditor({
    heartbeatType: 'answer',
    autoActivateHeartbeat: false,
    convertImagesToLinks: true,
    noModals: true,
    showLowRepImageUploadWarning: true,
    reputationToPostImages: 10,
    bindNavPrevention: true,
    postfix: "",
    imageUploader: {
    brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
    contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
    allowUrls: true
    },
    onDemand: true,
    discardSelector: ".discard-answer"
    ,immediatelyShowMarkdownHelp:true
    });


    }
    });














    draft saved

    draft discarded


















    StackExchange.ready(
    function () {
    StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f55136414%2fconstexpr-variable-captured-inside-lambda-loses-its-constexpr-ness%23new-answer', 'question_page');
    }
    );

    Post as a guest















    Required, but never shown

























    2 Answers
    2






    active

    oldest

    votes








    2 Answers
    2






    active

    oldest

    votes









    active

    oldest

    votes






    active

    oldest

    votes









    14














    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.






    share|improve this answer


























    • Is there a location in the C++ standard where this is stated?

      – Nicol Bolas
      12 hours ago











    • Indeed, C++17 seems to directly contradict this. b is implicitly captured by the lambda; there is no caveat about being a constant expression.

      – Nicol Bolas
      12 hours ago








    • 3





      @NicolBolas since b is constexpr, performing an lvalue-to-rvalue conversion on it directly does not constitute an odr-use. See [basic.def.odr]/3 for the standard reference.

      – Brian
      11 hours ago
















    14














    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.






    share|improve this answer


























    • Is there a location in the C++ standard where this is stated?

      – Nicol Bolas
      12 hours ago











    • Indeed, C++17 seems to directly contradict this. b is implicitly captured by the lambda; there is no caveat about being a constant expression.

      – Nicol Bolas
      12 hours ago








    • 3





      @NicolBolas since b is constexpr, performing an lvalue-to-rvalue conversion on it directly does not constitute an odr-use. See [basic.def.odr]/3 for the standard reference.

      – Brian
      11 hours ago














    14












    14








    14







    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.






    share|improve this answer















    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.







    share|improve this answer














    share|improve this answer



    share|improve this answer








    edited 12 hours ago

























    answered 19 hours ago









    songyuanyaosongyuanyao

    92.9k11178244




    92.9k11178244













    • Is there a location in the C++ standard where this is stated?

      – Nicol Bolas
      12 hours ago











    • Indeed, C++17 seems to directly contradict this. b is implicitly captured by the lambda; there is no caveat about being a constant expression.

      – Nicol Bolas
      12 hours ago








    • 3





      @NicolBolas since b is constexpr, performing an lvalue-to-rvalue conversion on it directly does not constitute an odr-use. See [basic.def.odr]/3 for the standard reference.

      – Brian
      11 hours ago



















    • Is there a location in the C++ standard where this is stated?

      – Nicol Bolas
      12 hours ago











    • Indeed, C++17 seems to directly contradict this. b is implicitly captured by the lambda; there is no caveat about being a constant expression.

      – Nicol Bolas
      12 hours ago








    • 3





      @NicolBolas since b is constexpr, performing an lvalue-to-rvalue conversion on it directly does not constitute an odr-use. See [basic.def.odr]/3 for the standard reference.

      – Brian
      11 hours ago

















    Is there a location in the C++ standard where this is stated?

    – Nicol Bolas
    12 hours ago





    Is there a location in the C++ standard where this is stated?

    – Nicol Bolas
    12 hours ago













    Indeed, C++17 seems to directly contradict this. b is implicitly captured by the lambda; there is no caveat about being a constant expression.

    – Nicol Bolas
    12 hours ago







    Indeed, C++17 seems to directly contradict this. b is implicitly captured by the lambda; there is no caveat about being a constant expression.

    – Nicol Bolas
    12 hours ago






    3




    3





    @NicolBolas since b is constexpr, performing an lvalue-to-rvalue conversion on it directly does not constitute an odr-use. See [basic.def.odr]/3 for the standard reference.

    – Brian
    11 hours ago





    @NicolBolas since b is constexpr, performing an lvalue-to-rvalue conversion on it directly does not constitute an odr-use. See [basic.def.odr]/3 for the standard reference.

    – Brian
    11 hours ago













    7















    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






    share|improve this answer






























      7















      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






      share|improve this answer




























        7












        7








        7








        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






        share|improve this answer
















        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







        share|improve this answer














        share|improve this answer



        share|improve this answer








        edited 15 hours ago

























        answered 19 hours ago









        P.WP.W

        16.4k31455




        16.4k31455






























            draft saved

            draft discarded




















































            Thanks for contributing an answer to Stack Overflow!


            • Please be sure to answer the question. Provide details and share your research!

            But avoid



            • Asking for help, clarification, or responding to other answers.

            • Making statements based on opinion; back them up with references or personal experience.


            To learn more, see our tips on writing great answers.




            draft saved


            draft discarded














            StackExchange.ready(
            function () {
            StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f55136414%2fconstexpr-variable-captured-inside-lambda-loses-its-constexpr-ness%23new-answer', 'question_page');
            }
            );

            Post as a guest















            Required, but never shown





















































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown

































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown







            Popular posts from this blog

            Plaza Victoria

            Puebla de Zaragoza

            Musa