Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • World
  • Users
  • Groups
Skins
  • Light
  • Cerulean
  • Cosmo
  • Flatly
  • Journal
  • Litera
  • Lumen
  • Lux
  • Materia
  • Minty
  • Morph
  • Pulse
  • Sandstone
  • Simplex
  • Sketchy
  • Spacelab
  • United
  • Yeti
  • Zephyr
  • Dark
  • Cyborg
  • Darkly
  • Quartz
  • Slate
  • Solar
  • Superhero
  • Vapor

  • Default (No Skin)
  • No Skin
Collapse
Code Project
  1. Home
  2. General Programming
  3. ATL / WTL / STL
  4. using for_each

using for_each

Scheduled Pinned Locked Moved ATL / WTL / STL
question
7 Posts 4 Posters 0 Views 1 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • P Offline
    P Offline
    paulb
    wrote on last edited by
    #1

    I have this explicit loop:

    FileMap::iterator it;
    for (it = outputFiles.begin(); it != outputFiles.end(); it++)
    {
    it->second->close();
    }

    where FileMap is a map<string,ofstream*>, so the loop is just going through all the stream pointers and calling close() on them is it possible to implement this using for_each?, I tried this but got compiler errors:

    for_each(outputFiles.begin(), outputFiles.end(), std::mem_fun(&std::ofstream::close));

    V A J 3 Replies Last reply
    0
    • P paulb

      I have this explicit loop:

      FileMap::iterator it;
      for (it = outputFiles.begin(); it != outputFiles.end(); it++)
      {
      it->second->close();
      }

      where FileMap is a map<string,ofstream*>, so the loop is just going through all the stream pointers and calling close() on them is it possible to implement this using for_each?, I tried this but got compiler errors:

      for_each(outputFiles.begin(), outputFiles.end(), std::mem_fun(&std::ofstream::close));

      V Offline
      V Offline
      valikac
      wrote on last edited by
      #2

      map is a key/value type of container. Try a vector or something one dimensional. Kuphryn

      1 Reply Last reply
      0
      • P paulb

        I have this explicit loop:

        FileMap::iterator it;
        for (it = outputFiles.begin(); it != outputFiles.end(); it++)
        {
        it->second->close();
        }

        where FileMap is a map<string,ofstream*>, so the loop is just going through all the stream pointers and calling close() on them is it possible to implement this using for_each?, I tried this but got compiler errors:

        for_each(outputFiles.begin(), outputFiles.end(), std::mem_fun(&std::ofstream::close));

        A Offline
        A Offline
        Andrew Walker
        wrote on last edited by
        #3

        Yes, it is doable, but not using 'clean' STL design ideas. remember that the type of the element in the map is std::pair<string,ofstream*>, not just ofstream or ofstream*, so you need to compensate for that. The easiest way I can think of is to use lambda expressions (see boost::lambda for a comprehensive library). Personally, I feel that lambda libraries are shakey ground at the moment. Most developers have enough trouble reading normal STL constructs without adding in strange things like '_1'and '_2' - but it depends on how comfortable with STL you and your co-workers are. Just as an aside, are you sure that you really want to do this? Assuming that you dynamically creating the files why don't you rely upon the destructors to close the files for you - if this is the behavior that you want use boost::shared_ptr to keep a reference counter handle to the files, and when the map goes out of scope, all the files will be taken with it. The only other reason I can think that you would want to do this is to reuse the files, if you are doing this make sure that you test thoroughly Herb Sutter (the convenor of the C++ standards committee) documented some interesting 'features' (read: issues) of ofstream's after they have recycled in a recent issue of the C/C++ Users Journal. After all that, if you're prepared to compromise on a 'dirty' rewrite for_each to work nicely with pairs, use the normal loop or try the following: void closer(const std::pair<string,ofstream*>& toClose) { toClose.second->close(); } for_each(outputFiles.begin(), outputFiles.end(), closer); In this case I think your original loop really does make things a lot clearer than it would otherwise be.


        If you can keep you head when all about you Are losing theirs and blaming it on you; If you can dream - and not make dreams your master; If you can think - and not make thoughts you aim; Yours is the Earth and everything that's in it. Rudyard Kipling

        P 1 Reply Last reply
        0
        • A Andrew Walker

          Yes, it is doable, but not using 'clean' STL design ideas. remember that the type of the element in the map is std::pair<string,ofstream*>, not just ofstream or ofstream*, so you need to compensate for that. The easiest way I can think of is to use lambda expressions (see boost::lambda for a comprehensive library). Personally, I feel that lambda libraries are shakey ground at the moment. Most developers have enough trouble reading normal STL constructs without adding in strange things like '_1'and '_2' - but it depends on how comfortable with STL you and your co-workers are. Just as an aside, are you sure that you really want to do this? Assuming that you dynamically creating the files why don't you rely upon the destructors to close the files for you - if this is the behavior that you want use boost::shared_ptr to keep a reference counter handle to the files, and when the map goes out of scope, all the files will be taken with it. The only other reason I can think that you would want to do this is to reuse the files, if you are doing this make sure that you test thoroughly Herb Sutter (the convenor of the C++ standards committee) documented some interesting 'features' (read: issues) of ofstream's after they have recycled in a recent issue of the C/C++ Users Journal. After all that, if you're prepared to compromise on a 'dirty' rewrite for_each to work nicely with pairs, use the normal loop or try the following: void closer(const std::pair<string,ofstream*>& toClose) { toClose.second->close(); } for_each(outputFiles.begin(), outputFiles.end(), closer); In this case I think your original loop really does make things a lot clearer than it would otherwise be.


          If you can keep you head when all about you Are losing theirs and blaming it on you; If you can dream - and not make dreams your master; If you can think - and not make thoughts you aim; Yours is the Earth and everything that's in it. Rudyard Kipling

          P Offline
          P Offline
          paulb
          wrote on last edited by
          #4

          Thanks for that, that has cleared things up a lot for this STL newbie. I am trying to make more use of the STL algorithms in my code, but in this case I will stick with the for loop, for clarity.

          1 Reply Last reply
          0
          • P paulb

            I have this explicit loop:

            FileMap::iterator it;
            for (it = outputFiles.begin(); it != outputFiles.end(); it++)
            {
            it->second->close();
            }

            where FileMap is a map<string,ofstream*>, so the loop is just going through all the stream pointers and calling close() on them is it possible to implement this using for_each?, I tried this but got compiler errors:

            for_each(outputFiles.begin(), outputFiles.end(), std::mem_fun(&std::ofstream::close));

            J Offline
            J Offline
            Jorgen Sigvardsson
            wrote on last edited by
            #5

            There is another thing you could add to Andrew's answer, without pulling in "weird lambda" stuff. This is what I'd do. Add a function called select_second like this:

            template <typename TPair>
            struct select_second : public std::unary_function<TPair, typename TPair::second_type> {
            result_type operator()(argument_type p) const {
            return p.second;
            }
            };

            then add a composer function like this:

            // It takes 2 functors, f and g, and compose them into f o g, i.e., f(g(x))
            template <typename F, typename G>
            struct composed_fn : public std::unary_function<typename G::argument_type, typename F::result_type> {
            const G& g;
            const F& f;
            composed_fn(const F& f_, const G& g_) : g(g_), f(f_) { }

            result_type operator()(argument_type x) const {
            return f(g(x));
            }
            };

            template <typename F, typename G>
            composed_fn<F, G> compose(const F& f, const G& g) {
            return composed_fn<F, G>(f, g);
            }

            Then you ought to be able to do something like:

            for_each(outputFiles.begin(), outputFiles.end(), compose(std::mem_fun(&std::ofstream::close), select_secondFileMap::value\_type()));

            I'm not sure if functional composition is possible in boost without the use of the "obscure" lambda library. If it is, please use boost instead. It's good and solid code. However, I've used this code myself for a while, and I've found it to be useful. It's easy to follow and understand if you have a grasp of templates and functors. f(g(x)) shouldn't be a surprise to anyone, it's basic high school mathematics. :) -- Booohoo!

            A 1 Reply Last reply
            0
            • J Jorgen Sigvardsson

              There is another thing you could add to Andrew's answer, without pulling in "weird lambda" stuff. This is what I'd do. Add a function called select_second like this:

              template <typename TPair>
              struct select_second : public std::unary_function<TPair, typename TPair::second_type> {
              result_type operator()(argument_type p) const {
              return p.second;
              }
              };

              then add a composer function like this:

              // It takes 2 functors, f and g, and compose them into f o g, i.e., f(g(x))
              template <typename F, typename G>
              struct composed_fn : public std::unary_function<typename G::argument_type, typename F::result_type> {
              const G& g;
              const F& f;
              composed_fn(const F& f_, const G& g_) : g(g_), f(f_) { }

              result_type operator()(argument_type x) const {
              return f(g(x));
              }
              };

              template <typename F, typename G>
              composed_fn<F, G> compose(const F& f, const G& g) {
              return composed_fn<F, G>(f, g);
              }

              Then you ought to be able to do something like:

              for_each(outputFiles.begin(), outputFiles.end(), compose(std::mem_fun(&std::ofstream::close), select_secondFileMap::value\_type()));

              I'm not sure if functional composition is possible in boost without the use of the "obscure" lambda library. If it is, please use boost instead. It's good and solid code. However, I've used this code myself for a while, and I've found it to be useful. It's easy to follow and understand if you have a grasp of templates and functors. f(g(x)) shouldn't be a surprise to anyone, it's basic high school mathematics. :) -- Booohoo!

              A Offline
              A Offline
              Andrew Walker
              wrote on last edited by
              #6

              Thanks Jörgen, answers like this are why I love CodeProject, fully deserving of a five. Time to go back and fix some of that old code... Boost::Compose[^] Has been deprecated in favour of bind and lambda btw :)


              If you can keep you head when all about you Are losing theirs and blaming it on you; If you can dream - and not make dreams your master; If you can think - and not make thoughts you aim; Yours is the Earth and everything that's in it. Rudyard Kipling

              J 1 Reply Last reply
              0
              • A Andrew Walker

                Thanks Jörgen, answers like this are why I love CodeProject, fully deserving of a five. Time to go back and fix some of that old code... Boost::Compose[^] Has been deprecated in favour of bind and lambda btw :)


                If you can keep you head when all about you Are losing theirs and blaming it on you; If you can dream - and not make dreams your master; If you can think - and not make thoughts you aim; Yours is the Earth and everything that's in it. Rudyard Kipling

                J Offline
                J Offline
                Jorgen Sigvardsson
                wrote on last edited by
                #7

                Thanks for your kind words. :) Real soon now, I will be ending a java project (at least my involvement in it), and go straight back to C++. I can't wait. ;) I have a bunch of header files with code for dealing with composition. With a bit of luck, I'll see if I can gather enough strength and will to write an article about it later on. Sure, there's always boost, but I figure I can show the concepts of functional composition if I used my own code. I think just the awareness of these tricks makes STL a lot easier and more enjoyable to work with. -- Booohoo!

                1 Reply Last reply
                0
                Reply
                • Reply as topic
                Log in to reply
                • Oldest to Newest
                • Newest to Oldest
                • Most Votes


                • Login

                • Don't have an account? Register

                • Login or register to search.
                • First post
                  Last post
                0
                • Categories
                • Recent
                • Tags
                • Popular
                • World
                • Users
                • Groups