Capturing a lambda in another lambda can violate const qualifiers Unicorn Meta Zoo #1: Why...

Why isn't everyone flabbergasted about Bran's "gift"?

Can you stand up from being prone using Skirmisher outside of your turn?

Are these square matrices always diagonalisable?

Protagonist's race is hidden - should I reveal it?

Is a 5 watt UHF/VHF handheld considered QRP?

Second order approximation of the loss function (Deep learning book, 7.33)

Split coins into combinations of different denominations

Trumpet valves, lengths, and pitch

AI positioning circles within an arc at equal distances and heights

Does Feeblemind produce an ongoing magical effect that can be dispelled?

My bank got bought out, am I now going to have to start filing tax returns in a different state?

Did the Roman Empire have penal colonies?

What is the ongoing value of the Kanban board to the developers as opposed to management

How would this chord from "Rocket Man" be analyzed?

Multiple options vs single option UI

I preordered a game on my Xbox while on the home screen of my friend's account. Which of us owns the game?

What is the least dense liquid under normal conditions?

What ability score does a Hexblade's Pact Weapon use for attack and damage when wielded by another character?

How do I check if a string is entirely made of the same substring?

Is it OK if I do not take the receipt in Germany?

Is Diceware more secure than a long passphrase?

Book with legacy programming code on a space ship that the main character hacks to escape

Arriving in Atlanta after US Preclearance in Dublin. Will I go through TSA security in Atlanta to transfer to a connecting flight?

Co-worker works way more than he should



Capturing a lambda in another lambda can violate const qualifiers



Unicorn Meta Zoo #1: Why another podcast?
Announcing the arrival of Valued Associate #679: Cesar Manara
Data science time! April 2019 and salary with experience
The Ask Question Wizard is Live!A const std::function wraps a non-const operator() / mutable lambdaC++ nested lambda bug in VS2010 with lambda parameter capture?C++ template allows discard of const reference qualifierPassing capturing lambda as function pointerlambdas: this capture ignores constness (vs std::bind)Why type const double is not captured by lambda from reaching-scope, but const int is?Non mutable lambda function: are copy-captured variables allowed to be const?GCC and Clang disagree about C++17 constexpr lambda capturesCapturing array of vectors in lambda makes elements constC++11 - lambda function pass vector in capture and modify itCopying object into lambda capture





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







23















Consider the following code:



int x = 3;
auto f1 = [x]() mutable
{
return x++;
};
auto f2 = [f1]()
{
return f1();
};


This will not compile, because f1() is not const, and f2 is not declared as mutable. Does this mean that if I have a library function that accepts an arbitrary function argument and captures it in a lambda, I always need to make that lambda mutable, because I don't know what users can pass in? Notably, wrapping f1 in std::function seems to resolve this problem (how?).










share|improve this question


















  • 1





    As a side note, that's the case with most of the Rust's functions, where they explicitly accept FnMut (even though in case of e.g. fold it would probably be called with Fn most of the time)

    – Bartek Banachewicz
    17 hours ago













  • Possible duplicate of A const std::function wraps a non-const operator() / mutable lambda

    – rustyx
    16 hours ago











  • @rustyx thanks, that answers the last point, but not the whole question.

    – riv
    15 hours ago






  • 2





    A "lambda violating const qualifiers" sounds like something out of a sci-fi movie.

    – LogicalBranch
    9 hours ago


















23















Consider the following code:



int x = 3;
auto f1 = [x]() mutable
{
return x++;
};
auto f2 = [f1]()
{
return f1();
};


This will not compile, because f1() is not const, and f2 is not declared as mutable. Does this mean that if I have a library function that accepts an arbitrary function argument and captures it in a lambda, I always need to make that lambda mutable, because I don't know what users can pass in? Notably, wrapping f1 in std::function seems to resolve this problem (how?).










share|improve this question


















  • 1





    As a side note, that's the case with most of the Rust's functions, where they explicitly accept FnMut (even though in case of e.g. fold it would probably be called with Fn most of the time)

    – Bartek Banachewicz
    17 hours ago













  • Possible duplicate of A const std::function wraps a non-const operator() / mutable lambda

    – rustyx
    16 hours ago











  • @rustyx thanks, that answers the last point, but not the whole question.

    – riv
    15 hours ago






  • 2





    A "lambda violating const qualifiers" sounds like something out of a sci-fi movie.

    – LogicalBranch
    9 hours ago














23












23








23


3






Consider the following code:



int x = 3;
auto f1 = [x]() mutable
{
return x++;
};
auto f2 = [f1]()
{
return f1();
};


This will not compile, because f1() is not const, and f2 is not declared as mutable. Does this mean that if I have a library function that accepts an arbitrary function argument and captures it in a lambda, I always need to make that lambda mutable, because I don't know what users can pass in? Notably, wrapping f1 in std::function seems to resolve this problem (how?).










share|improve this question














Consider the following code:



int x = 3;
auto f1 = [x]() mutable
{
return x++;
};
auto f2 = [f1]()
{
return f1();
};


This will not compile, because f1() is not const, and f2 is not declared as mutable. Does this mean that if I have a library function that accepts an arbitrary function argument and captures it in a lambda, I always need to make that lambda mutable, because I don't know what users can pass in? Notably, wrapping f1 in std::function seems to resolve this problem (how?).







c++ lambda






share|improve this question













share|improve this question











share|improve this question




share|improve this question










asked 17 hours ago









rivriv

3,65211433




3,65211433








  • 1





    As a side note, that's the case with most of the Rust's functions, where they explicitly accept FnMut (even though in case of e.g. fold it would probably be called with Fn most of the time)

    – Bartek Banachewicz
    17 hours ago













  • Possible duplicate of A const std::function wraps a non-const operator() / mutable lambda

    – rustyx
    16 hours ago











  • @rustyx thanks, that answers the last point, but not the whole question.

    – riv
    15 hours ago






  • 2





    A "lambda violating const qualifiers" sounds like something out of a sci-fi movie.

    – LogicalBranch
    9 hours ago














  • 1





    As a side note, that's the case with most of the Rust's functions, where they explicitly accept FnMut (even though in case of e.g. fold it would probably be called with Fn most of the time)

    – Bartek Banachewicz
    17 hours ago













  • Possible duplicate of A const std::function wraps a non-const operator() / mutable lambda

    – rustyx
    16 hours ago











  • @rustyx thanks, that answers the last point, but not the whole question.

    – riv
    15 hours ago






  • 2





    A "lambda violating const qualifiers" sounds like something out of a sci-fi movie.

    – LogicalBranch
    9 hours ago








1




1





As a side note, that's the case with most of the Rust's functions, where they explicitly accept FnMut (even though in case of e.g. fold it would probably be called with Fn most of the time)

– Bartek Banachewicz
17 hours ago







As a side note, that's the case with most of the Rust's functions, where they explicitly accept FnMut (even though in case of e.g. fold it would probably be called with Fn most of the time)

– Bartek Banachewicz
17 hours ago















Possible duplicate of A const std::function wraps a non-const operator() / mutable lambda

– rustyx
16 hours ago





Possible duplicate of A const std::function wraps a non-const operator() / mutable lambda

– rustyx
16 hours ago













@rustyx thanks, that answers the last point, but not the whole question.

– riv
15 hours ago





@rustyx thanks, that answers the last point, but not the whole question.

– riv
15 hours ago




2




2





A "lambda violating const qualifiers" sounds like something out of a sci-fi movie.

– LogicalBranch
9 hours ago





A "lambda violating const qualifiers" sounds like something out of a sci-fi movie.

– LogicalBranch
9 hours ago












2 Answers
2






active

oldest

votes


















19















Does this mean that if I have a library function that accepts an arbitrary function argument and captures it in a lambda, I always need to make that lambda mutable, because I don't know what users can pass in?




That's a design decision for your library API. You can require client code to pass function objects with a const-qualified operator() (which is the case for non-mutable lambda expressions). If something different is passed, a compiler error is triggered. But if the context might require a function object argument that modifies its state, then yes, you have to make the internal lambda mutable.



An alternative would be to dispatch on the ability to invoke operator() on a const-qualified instance of the given function type. Something along those lines (note that this needs a fix for function objects with both const and non-const operator(), which results in an ambiguity):



template <class Fct>
auto wrap(Fct&& f) -> decltype(f(), void())
{
[fct = std::forward<Fct>(f)]() mutable { fct(); }();
}

template <class Fct>
auto wrap(Fct&& f) -> decltype(std::declval<const Fct&>()(), void())
{
[fct = std::forward<Fct>(f)]() { fct(); }();
}



Notably, wrapping f1 in std::function seems to resolve this problem (how?).




This is a bug in std::function due to its type-erasure and copy semantics. It allows non-const-qualified operator() to be invoked, which can be verified with such a snippet:



const std::function<void()> f = [i = 0]() mutable { ++i; };

f(); // Shouldn't be possible, but unfortunately, it is


This is a known issue, it's worth checking out Titus Winter's complaint on this.






share|improve this answer

































    5














    I'll start by addressing your second question first. std::function type erases, and holds a copy of the functor it's initialized with. That means there's a layer of indirection between std::function::operator() and the actual functor's operator().



    Envision if you will, holding something in your class by pointer. Then you may call a mutating operation on the pointee from a const member function of your class, because it doesn't affect (in a shallow view) the pointer that the class holds. This is a similar situation to what you observed.



    As for your first question... "Always" is too strong a word. It depends on your goal.




    1. If you want to support self mutating functors easily, then you should capture in a mutable lambda. But beware it may affect the library functions you may call now.


    2. If you wish to favor non-mutating operations, then a non-mutable lambda. I say "favor" because as we observed, the type system can be "fooled" with an extra level of indirection. So the approach you prefer is only going to be easier to use, not impossible to go around. This is as the sage advice goes, make correct use of your API easy, and incorrect harder.







    share|improve this answer



















    • 1





      Notably, wrapping a passed lambda in std::ref provides the level of indirection that allows mutability even in const contexts. It also gets around the "functors may be copied around in the implementation" if you are after tracking some state.

      – Max Langhof
      16 hours ago













    • Ah, I see it became a hot network post.

      – StoryTeller
      16 hours ago












    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%2f55826592%2fcapturing-a-lambda-in-another-lambda-can-violate-const-qualifiers%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









    19















    Does this mean that if I have a library function that accepts an arbitrary function argument and captures it in a lambda, I always need to make that lambda mutable, because I don't know what users can pass in?




    That's a design decision for your library API. You can require client code to pass function objects with a const-qualified operator() (which is the case for non-mutable lambda expressions). If something different is passed, a compiler error is triggered. But if the context might require a function object argument that modifies its state, then yes, you have to make the internal lambda mutable.



    An alternative would be to dispatch on the ability to invoke operator() on a const-qualified instance of the given function type. Something along those lines (note that this needs a fix for function objects with both const and non-const operator(), which results in an ambiguity):



    template <class Fct>
    auto wrap(Fct&& f) -> decltype(f(), void())
    {
    [fct = std::forward<Fct>(f)]() mutable { fct(); }();
    }

    template <class Fct>
    auto wrap(Fct&& f) -> decltype(std::declval<const Fct&>()(), void())
    {
    [fct = std::forward<Fct>(f)]() { fct(); }();
    }



    Notably, wrapping f1 in std::function seems to resolve this problem (how?).




    This is a bug in std::function due to its type-erasure and copy semantics. It allows non-const-qualified operator() to be invoked, which can be verified with such a snippet:



    const std::function<void()> f = [i = 0]() mutable { ++i; };

    f(); // Shouldn't be possible, but unfortunately, it is


    This is a known issue, it's worth checking out Titus Winter's complaint on this.






    share|improve this answer






























      19















      Does this mean that if I have a library function that accepts an arbitrary function argument and captures it in a lambda, I always need to make that lambda mutable, because I don't know what users can pass in?




      That's a design decision for your library API. You can require client code to pass function objects with a const-qualified operator() (which is the case for non-mutable lambda expressions). If something different is passed, a compiler error is triggered. But if the context might require a function object argument that modifies its state, then yes, you have to make the internal lambda mutable.



      An alternative would be to dispatch on the ability to invoke operator() on a const-qualified instance of the given function type. Something along those lines (note that this needs a fix for function objects with both const and non-const operator(), which results in an ambiguity):



      template <class Fct>
      auto wrap(Fct&& f) -> decltype(f(), void())
      {
      [fct = std::forward<Fct>(f)]() mutable { fct(); }();
      }

      template <class Fct>
      auto wrap(Fct&& f) -> decltype(std::declval<const Fct&>()(), void())
      {
      [fct = std::forward<Fct>(f)]() { fct(); }();
      }



      Notably, wrapping f1 in std::function seems to resolve this problem (how?).




      This is a bug in std::function due to its type-erasure and copy semantics. It allows non-const-qualified operator() to be invoked, which can be verified with such a snippet:



      const std::function<void()> f = [i = 0]() mutable { ++i; };

      f(); // Shouldn't be possible, but unfortunately, it is


      This is a known issue, it's worth checking out Titus Winter's complaint on this.






      share|improve this answer




























        19












        19








        19








        Does this mean that if I have a library function that accepts an arbitrary function argument and captures it in a lambda, I always need to make that lambda mutable, because I don't know what users can pass in?




        That's a design decision for your library API. You can require client code to pass function objects with a const-qualified operator() (which is the case for non-mutable lambda expressions). If something different is passed, a compiler error is triggered. But if the context might require a function object argument that modifies its state, then yes, you have to make the internal lambda mutable.



        An alternative would be to dispatch on the ability to invoke operator() on a const-qualified instance of the given function type. Something along those lines (note that this needs a fix for function objects with both const and non-const operator(), which results in an ambiguity):



        template <class Fct>
        auto wrap(Fct&& f) -> decltype(f(), void())
        {
        [fct = std::forward<Fct>(f)]() mutable { fct(); }();
        }

        template <class Fct>
        auto wrap(Fct&& f) -> decltype(std::declval<const Fct&>()(), void())
        {
        [fct = std::forward<Fct>(f)]() { fct(); }();
        }



        Notably, wrapping f1 in std::function seems to resolve this problem (how?).




        This is a bug in std::function due to its type-erasure and copy semantics. It allows non-const-qualified operator() to be invoked, which can be verified with such a snippet:



        const std::function<void()> f = [i = 0]() mutable { ++i; };

        f(); // Shouldn't be possible, but unfortunately, it is


        This is a known issue, it's worth checking out Titus Winter's complaint on this.






        share|improve this answer
















        Does this mean that if I have a library function that accepts an arbitrary function argument and captures it in a lambda, I always need to make that lambda mutable, because I don't know what users can pass in?




        That's a design decision for your library API. You can require client code to pass function objects with a const-qualified operator() (which is the case for non-mutable lambda expressions). If something different is passed, a compiler error is triggered. But if the context might require a function object argument that modifies its state, then yes, you have to make the internal lambda mutable.



        An alternative would be to dispatch on the ability to invoke operator() on a const-qualified instance of the given function type. Something along those lines (note that this needs a fix for function objects with both const and non-const operator(), which results in an ambiguity):



        template <class Fct>
        auto wrap(Fct&& f) -> decltype(f(), void())
        {
        [fct = std::forward<Fct>(f)]() mutable { fct(); }();
        }

        template <class Fct>
        auto wrap(Fct&& f) -> decltype(std::declval<const Fct&>()(), void())
        {
        [fct = std::forward<Fct>(f)]() { fct(); }();
        }



        Notably, wrapping f1 in std::function seems to resolve this problem (how?).




        This is a bug in std::function due to its type-erasure and copy semantics. It allows non-const-qualified operator() to be invoked, which can be verified with such a snippet:



        const std::function<void()> f = [i = 0]() mutable { ++i; };

        f(); // Shouldn't be possible, but unfortunately, it is


        This is a known issue, it's worth checking out Titus Winter's complaint on this.







        share|improve this answer














        share|improve this answer



        share|improve this answer








        edited 16 hours ago

























        answered 17 hours ago









        lubgrlubgr

        16.2k32557




        16.2k32557

























            5














            I'll start by addressing your second question first. std::function type erases, and holds a copy of the functor it's initialized with. That means there's a layer of indirection between std::function::operator() and the actual functor's operator().



            Envision if you will, holding something in your class by pointer. Then you may call a mutating operation on the pointee from a const member function of your class, because it doesn't affect (in a shallow view) the pointer that the class holds. This is a similar situation to what you observed.



            As for your first question... "Always" is too strong a word. It depends on your goal.




            1. If you want to support self mutating functors easily, then you should capture in a mutable lambda. But beware it may affect the library functions you may call now.


            2. If you wish to favor non-mutating operations, then a non-mutable lambda. I say "favor" because as we observed, the type system can be "fooled" with an extra level of indirection. So the approach you prefer is only going to be easier to use, not impossible to go around. This is as the sage advice goes, make correct use of your API easy, and incorrect harder.







            share|improve this answer



















            • 1





              Notably, wrapping a passed lambda in std::ref provides the level of indirection that allows mutability even in const contexts. It also gets around the "functors may be copied around in the implementation" if you are after tracking some state.

              – Max Langhof
              16 hours ago













            • Ah, I see it became a hot network post.

              – StoryTeller
              16 hours ago
















            5














            I'll start by addressing your second question first. std::function type erases, and holds a copy of the functor it's initialized with. That means there's a layer of indirection between std::function::operator() and the actual functor's operator().



            Envision if you will, holding something in your class by pointer. Then you may call a mutating operation on the pointee from a const member function of your class, because it doesn't affect (in a shallow view) the pointer that the class holds. This is a similar situation to what you observed.



            As for your first question... "Always" is too strong a word. It depends on your goal.




            1. If you want to support self mutating functors easily, then you should capture in a mutable lambda. But beware it may affect the library functions you may call now.


            2. If you wish to favor non-mutating operations, then a non-mutable lambda. I say "favor" because as we observed, the type system can be "fooled" with an extra level of indirection. So the approach you prefer is only going to be easier to use, not impossible to go around. This is as the sage advice goes, make correct use of your API easy, and incorrect harder.







            share|improve this answer



















            • 1





              Notably, wrapping a passed lambda in std::ref provides the level of indirection that allows mutability even in const contexts. It also gets around the "functors may be copied around in the implementation" if you are after tracking some state.

              – Max Langhof
              16 hours ago













            • Ah, I see it became a hot network post.

              – StoryTeller
              16 hours ago














            5












            5








            5







            I'll start by addressing your second question first. std::function type erases, and holds a copy of the functor it's initialized with. That means there's a layer of indirection between std::function::operator() and the actual functor's operator().



            Envision if you will, holding something in your class by pointer. Then you may call a mutating operation on the pointee from a const member function of your class, because it doesn't affect (in a shallow view) the pointer that the class holds. This is a similar situation to what you observed.



            As for your first question... "Always" is too strong a word. It depends on your goal.




            1. If you want to support self mutating functors easily, then you should capture in a mutable lambda. But beware it may affect the library functions you may call now.


            2. If you wish to favor non-mutating operations, then a non-mutable lambda. I say "favor" because as we observed, the type system can be "fooled" with an extra level of indirection. So the approach you prefer is only going to be easier to use, not impossible to go around. This is as the sage advice goes, make correct use of your API easy, and incorrect harder.







            share|improve this answer













            I'll start by addressing your second question first. std::function type erases, and holds a copy of the functor it's initialized with. That means there's a layer of indirection between std::function::operator() and the actual functor's operator().



            Envision if you will, holding something in your class by pointer. Then you may call a mutating operation on the pointee from a const member function of your class, because it doesn't affect (in a shallow view) the pointer that the class holds. This is a similar situation to what you observed.



            As for your first question... "Always" is too strong a word. It depends on your goal.




            1. If you want to support self mutating functors easily, then you should capture in a mutable lambda. But beware it may affect the library functions you may call now.


            2. If you wish to favor non-mutating operations, then a non-mutable lambda. I say "favor" because as we observed, the type system can be "fooled" with an extra level of indirection. So the approach you prefer is only going to be easier to use, not impossible to go around. This is as the sage advice goes, make correct use of your API easy, and incorrect harder.








            share|improve this answer












            share|improve this answer



            share|improve this answer










            answered 17 hours ago









            StoryTellerStoryTeller

            106k14223287




            106k14223287








            • 1





              Notably, wrapping a passed lambda in std::ref provides the level of indirection that allows mutability even in const contexts. It also gets around the "functors may be copied around in the implementation" if you are after tracking some state.

              – Max Langhof
              16 hours ago













            • Ah, I see it became a hot network post.

              – StoryTeller
              16 hours ago














            • 1





              Notably, wrapping a passed lambda in std::ref provides the level of indirection that allows mutability even in const contexts. It also gets around the "functors may be copied around in the implementation" if you are after tracking some state.

              – Max Langhof
              16 hours ago













            • Ah, I see it became a hot network post.

              – StoryTeller
              16 hours ago








            1




            1





            Notably, wrapping a passed lambda in std::ref provides the level of indirection that allows mutability even in const contexts. It also gets around the "functors may be copied around in the implementation" if you are after tracking some state.

            – Max Langhof
            16 hours ago







            Notably, wrapping a passed lambda in std::ref provides the level of indirection that allows mutability even in const contexts. It also gets around the "functors may be copied around in the implementation" if you are after tracking some state.

            – Max Langhof
            16 hours ago















            Ah, I see it became a hot network post.

            – StoryTeller
            16 hours ago





            Ah, I see it became a hot network post.

            – StoryTeller
            16 hours ago


















            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%2f55826592%2fcapturing-a-lambda-in-another-lambda-can-violate-const-qualifiers%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

            VNC viewer RFB protocol error: bad desktop size 0x0I Cannot Type the Key 'd' (lowercase) in VNC Viewer...

            Tribunal Administrativo e Fiscal de Mirandela Referências Menu de...

            looking for continuous Screen Capture for retroactivly reproducing errors, timeback machineRolling desktop...