Sum first in std::pair using Boost.Bind

Dear PH users,

Does anybody known how to, from a vector of pairs, sum the first value of each pair?

On the web, some people have posted the answer, as I show here:

[code]
#include
#include
#include
#include

int main()
{
std::vector > v;
v.push_back(std::make_pair(0,0));
v.push_back(std::make_pair(1,1));
v.push_back(std::make_pair(2,4));
v.push_back(std::make_pair(3,9));

const int sum_first = std::accumulate(v.begin(),v.end(),
static_cast(0),
boost::bind(&std::pair::first,_1));
}
[/code]

Problem is, with GCC this does not compile. I use Boost library version 1.40 and the STL supplied with Qt Creator 2.0.0.

Anybody an idea how to get this to compile?

When I compile, I get the following error message:

[code]
/usr/include/boost/bind/mem_fn.hpp:333: error: no matching function for call to

Comments

  • Dear Bilderbikkel,

    I have encountered precisely the same problem as you, but I don't believe it to be a problem with either GCC or the Boost libraries. In fact, I think I have a solution for you:

    [code]#include
    #include
    #include
    #include

    #include // For std::cout, std::endl
    #include // For std::plus

    int main()
    {
    std::vector > v;
    v.push_back(std::make_pair(0,0));
    v.push_back(std::make_pair(1,1));
    v.push_back(std::make_pair(2,4));
    v.push_back(std::make_pair(3,9));

    const int sum_first = std::accumulate(v.begin(),v.end(),
    static_cast(0),
    boost::bind(
    std::plus(),
    _1,
    boost::bind(&std::pair::first, _2)
    )
    );

    // Disable warning: "unused variable 'sum_first'"
    std::cout << sum_first << std::endl;
    }
    [/code]
    Now the explanation:
    The first problem with the original code is that std::accumulate takes a binary_function as its final argument, which in turn takes:

    [code]Arg1: accumulated value
    Arg2: next value to be added[/code]
    So, the boost::binder was binding the wrong argument (argument: '_1', where it should have been: '_2').

    Next, this binder can only take a single argument (the std::pair to have its first element extracted), and so is a unary function. This is incompatible with std::accumulate.

    So, to turn this unary function into a binary function (a function taking two arguments), as required by std::accumulate, it's necessary to use another outer bind with an instance of std::plus (or equivalent) to combine the next value with the accumulated total so far.

    And that's it. Although it is somewhat complex (it takes more than a second to understand what's going on), the above code should do what you need. However, if you were to instead use boost::lambda, the code becomes a lot simpler:

    [code]#include <numeric>
    #include
    #include

    #include // For std::cout, std::endl
    #include
    #include

    int main()
    {
    std::vector > v;
    v.push_back(std::make_pair(0,0));
    v.push_back(std::make_pair(1,1));
    v.push_back(std::make_pair(2,4));
    v.push_back(std::make_pair(3,9));

    using boost::lambda::bind;
    using boost::lambda::_1;
    using boost::lambda::_2;

    const int sum_first = std::accumulate(v.begin(),v.end(),
    static_cast(0),
    _1 + bind(&std::pair::first, _2));

    // Disable warning: "unused variable 'sum_first'"
    std::cout << sum_first << std::endl;
    }[/code]
    (Both examples tested and working on GCC 4.4.3, with Boost 1.43.0.)

    Regards.
Sign In or Register to comment.

Howdy, Stranger!

It looks like you're new here. If you want to get involved, click one of these buttons!

Categories

In this Discussion