2

I have a Container of Elements, and each Element has its size() member function. I have managed to accumulate the total Container Elements size by writing a binary operation add_size:

#include <algorithm>
#include <vector>
#include <functional>
#include <numeric>
#include <iostream>

class A
{
    int size_ ; 

    public: 

        A ()
            :
                size_(0)
        {}

        A (int size)
            :
                size_(size)
        {}

        int size() const
        {
            return size_; 
        }
};

template<typename Type>
class add_element 
{
    Type t_; 

    public: 

        add_element(Type const & t)
            :
                t_(t)
        {}

        void operator()(Type & t)
        {
            t += t_; 
        }
};

int add_size (int i, const A& a)
{
    return i+=a.size();
}

using namespace std;

int main(int argc, const char *argv[])
{

    typedef vector<A> Vector;

    Vector v; 

    v.push_back(A(10));
    v.push_back(A(5));
    v.push_back(A(7));
    v.push_back(A(21));
    v.push_back(A(2));
    v.push_back(A(1));

    int totalSize = accumulate(v.begin(), v.end(), 0, add_size);

    std::cout << totalSize << endl;

    return 0;
}

This gives the correct output:

46

And what I would like is to do that without defining the binary operation add_size just for the size member function, but with using mem_fun and binders. How can I do that? How can I do that effectively? I started out with add_element and got stuck.

I need the solution to work in C++03.

TemplateRex
  • 69,038
  • 19
  • 164
  • 304
tmaric
  • 5,347
  • 4
  • 42
  • 75
  • How about boost::lambda? – ForEveR May 08 '13 at 10:01
  • @ForEveR that's C++11, right? I need the solution to work with C++03. The code runs on clusters with old compilers. – tmaric May 08 '13 at 10:01
  • 2
    boost != C++11. http://www.boost.org/ – ForEveR May 08 '13 at 10:02
  • @ForEveR, thanks, good to know. Still, I can't shouldn't introduce dependency to boost just because of this single thing. Is there no other way, like binders and mem_fun, or something like that? – tmaric May 08 '13 at 10:03
  • Why exactly do you want to not use that? elegance? – stardust May 08 '13 at 10:11
  • @Named, that and re-using code. – tmaric May 08 '13 at 10:12
  • @hjmd, okay, what happens if A is a set of 5 numbers, then A operator+(A const&, A const&) should not result in the sum of sizes of A objects, but in a sum of sets. – tmaric May 08 '13 at 10:13
  • I can see that it is not elegant. but I don't know what you mean by re-using code here. – stardust May 08 '13 at 10:14
  • @Named: maybe I am pushing things to extreme here... I don't have enough experience to tell if its so. :) So, each time I have a member function of an Element of a Container giving me an affine type (sum, divide, ..) I should roll my own loops? – tmaric May 08 '13 at 10:15
  • Define `A operator(A const&, A const&)`? http://ideone.com/8t2SEv – hmjd May 08 '13 at 10:16
  • @hjmd this breaks the set affine properties; sum of two sets is not the sum of their sizes. – tmaric May 08 '13 at 10:18
  • @tomislav-maric: *reusing code*? I believe it is possible to build such a thing with binders, but it will make the code much more complicated than a plain simple loop: `int sum = 0; for (std::vector::const_iterator it = v.begin(), end = v.end(); it != end; ++it ) sum += it->size();` There is no point in using algorithms/functors if the code is going to be harder to understand... – David Rodríguez - dribeas May 08 '13 at 12:21
  • If you absolutely, positively don't want to use C++11 or even Boost, your punishment is to choose between two evils: `std::mem_fun` and `std::bind1st`; or generating a vector of 1s and doing a `std::inner_product` on that with your data ;-) – TemplateRex May 08 '13 at 12:32
  • @tomislav-maric: *I should roll my own loops?* You have to balance the complexity of the solutions and choose. If you were using C++11 or C++14 features then the answer will be different. But doing what you ask with plain C++03 (and no library support like boost) is going to make the solution more complex than the problem. (You could roll out a generic binder that helps you build this... but both boost and C++11 have `bind`, and lambdas (different types). – David Rodríguez - dribeas May 08 '13 at 12:34
  • @rhalbersma: Can you really implement this with `std::men_fun` and `std::bind1st` (probably you meant `bind2nd`)?? – David Rodríguez - dribeas May 08 '13 at 12:35
  • @DavidRodríguez-dribeas, :) I don't know that's why I'm asking. :) – tmaric May 08 '13 at 12:41
  • @DavidRodríguez-dribeas I'd hate really having to think about it. `std::accumulate` expects a BinaryFunction, so it should be something of `std::plus` and `std::mem_fun` on the `size()` member. Anyway, this should be tagged `C++-antique` :) – TemplateRex May 08 '13 at 12:41
  • @rhalbersma... C++-antique is a good suggestion for a tag actually. :) – tmaric May 08 '13 at 12:46
  • 1
    @rhalbersma: The problem is binding the `std::plus` and the `std::men_fun` together... `std::bind` in C++11 can do it, but I am not sure that `std::bind2nd` in C++03 can. If you are willing to walk the walk... you can either pull boost into the dependencies or implement either a binder (complex) or an iterator adapter (simpler, not really *simple*), but I don't think that you can do this with raw C++03 and only the standard library without rolling out extra types. – David Rodríguez - dribeas May 08 '13 at 12:47
  • @DavidRodríguez-dribeas thanks! If you put this in as an answer I will +1 it. :) – tmaric May 08 '13 at 12:56
  • @DavidRodríguez-dribeas just wrote the "copy Boost" as an answer, missed your comment to that effect. – TemplateRex May 08 '13 at 12:59
  • Please take real time chat to our 'chat' site. Clarifications on posts should be made in the comments. New questions should be asked as such (as questions, not as comments), and clarifications to answers should be edited into answers. Comments are impermanent and may be deleted at any time. – George Stocker May 08 '13 at 13:01
  • @GeorgeStocker Point well taken, but I sure hope not this is a veiled hint at you moderating these comments yourself? – TemplateRex May 08 '13 at 13:07
  • @rhalbersma We get pinged in the queue any time there's a lot of comments on a post in a short amount of time. Too many of those happen and sooner or later the comments will be pruned (especially if it's shown they were a short lived conversation where both parties received resolution). This isn't a threat, it's just a statement of what happens when comments are abused for extended discussion purposes. – George Stocker May 08 '13 at 13:08

1 Answers1

2

I believe your question is ill-posed. Look at what you have: a small one-liner function add_size and a call to std::accumulate. What's not to like?

You are somehow (for perhaps corporate reasons) restricted from using either Boost.Bind or Boost.Lambda, let alone C++11 (which standardized both std::bind and lambda expressions).

You want to eliminate that in favor of the C++03 binders which are horribly limited in their expressiveness (which is BTW one reason why Boost.Bind and Boost.Lambda were so popular) and would require much more boilerplate than what you currently have. Look at this appendix of the C++ Standard Reference book by Nicolai Jusuttis. He implements a general compose template that works "nicely" with std::bind2nd and friends. But look at which headers he uses to implement that: right, the Boost.Bind ones.

Your best approach is to simply copy Boost.Bind and/or Boost.Lambda, put them in your own source tree, and rename the namespace to your company's. Check whether this is in fact consistent with the Boost License. Boost even has a bcp tool to extract all the included dependencies for you. Then simply write whatever you need to using the bind or lambda facilities that you've just "written".

TL;DR: Do not Re-invent the Wheel. Familiarize yourself with Boost.

TemplateRex
  • 69,038
  • 19
  • 164
  • 304
  • I have nothing against Familiarizing myself with Boost, and I didn't know the background of the story, since I lack the experience. Thank you for providing your insight into the problem! +1 – tmaric May 08 '13 at 13:02
  • @tomislav-maric Glad to have been of help. The "Familiarize yourself with Boost" is literally Item 55 of the excellent book [**Effective C++**](http://www.amazon.com/Effective-Specific-Improve-Programs-Designs/dp/0321334876), a [**must read**](http://stackoverflow.com/questions/388242/the-definitive-c-book-guide-and-list) if you want to expand your experience. – TemplateRex May 08 '13 at 13:05
  • :) I read that book... and More Effective, and I'm now reading Effective STL... I know how important boost is and I have a feel of what the new standard brings. My problem is that the code will be executed on hpc clusters with older compilers, so C++11 is out of the question, and I have no way of knowing which boost version lives on those machines, so I am worried because of that... – tmaric May 08 '13 at 13:07