Constexpr variable captured inside lambda loses its constexpr-ness

The name of the pictureThe name of the pictureThe name of the pictureClash Royale CLAN TAG#URR8PPP





.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty,.everyoneloves__bot-mid-leaderboard:empty height:90px;width:728px;box-sizing:border-box;








19















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
    Mar 13 at 7:29

















19















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
    Mar 13 at 7:29













19












19








19








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 Mar 13 at 7:30









HolyBlackCat

17.2k33568




17.2k33568










asked Mar 13 at 7:21









javaLoverjavaLover

2,7741939




2,7741939












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

    – HolyBlackCat
    Mar 13 at 7:29

















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

    – HolyBlackCat
    Mar 13 at 7:29
















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

– HolyBlackCat
Mar 13 at 7:29





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

– HolyBlackCat
Mar 13 at 7:29












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
    Mar 13 at 14:52











  • 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
    Mar 13 at 14:59







  • 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
    Mar 13 at 15:14


















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
      Mar 13 at 14:52











    • 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
      Mar 13 at 14:59







    • 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
      Mar 13 at 15: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

























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

      – Nicol Bolas
      Mar 13 at 14:52











    • 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
      Mar 13 at 14:59







    • 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
      Mar 13 at 15:14













    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 Mar 13 at 14:16

























    answered Mar 13 at 7:40









    songyuanyaosongyuanyao

    94.1k11182250




    94.1k11182250












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

      – Nicol Bolas
      Mar 13 at 14:52











    • 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
      Mar 13 at 14:59







    • 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
      Mar 13 at 15:14

















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

      – Nicol Bolas
      Mar 13 at 14:52











    • 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
      Mar 13 at 14:59







    • 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
      Mar 13 at 15:14
















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

    – Nicol Bolas
    Mar 13 at 14:52





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

    – Nicol Bolas
    Mar 13 at 14:52













    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
    Mar 13 at 14:59






    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
    Mar 13 at 14:59





    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
    Mar 13 at 15:14





    @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
    Mar 13 at 15:14













    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 Mar 13 at 12:01

























        answered Mar 13 at 7:40









        P.WP.W

        18.6k41758




        18.6k41758



























            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

            How to check contact read email or not when send email to Individual?

            Displaying single band from multi-band raster using QGIS

            How many registers does an x86_64 CPU actually have?