Q-bertsuit
Q-bertsuit

Reputation: 3437

STL algorithm/functional

I'm trying to use the transform algorithm (or any other part of the STL that would do the job) to change a sequence of ints. If the current element is more than 5, keep it. Else use 5.

This does not compile :

std::vector<int> vec;
vec.push_back(6);
vec.push_back(2);
vec.push_back(9);
vec.push_back(4);
vec.push_back(7);

std::transform(vec.begin(), vec.end(), vec.begin(), std::bind1st(std::max<int>(), 5));

I don't have access to C++11.

Upvotes: 2

Views: 253

Answers (4)

Vlad from Moscow
Vlad from Moscow

Reputation: 310940

For this task the more appropriate algorithm is std::replace_if . For example

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


int main() 
{
    std::vector<int> vec;

    vec.push_back( 6 );
    vec.push_back( 2 );
    vec.push_back( 9 );
    vec.push_back( 4 );
    vec.push_back( 7 );

    for ( std::vector<int>::size_type i = 0; i < vec.size(); i++ )
    {
        std::cout << vec[i] << ' ';
    }
    std::cout << std::endl;

    std::replace_if( vec.begin(), vec.end(),
                     std::bind2nd( std::less<int>(), 5 ), 5 );

    for ( std::vector<int>::size_type i = 0; i < vec.size(); i++ )
    {
        std::cout << vec[i] << ' ';
    }
    std::cout << std::endl;

    return 0;
}

The output is

6 2 9 4 7 
6 5 9 5 7 

Upvotes: 3

Konrad Rudolph
Konrad Rudolph

Reputation: 545528

You unfortunately cannot use bind* with function pointers directly. To work around this, you’d normally use std::ptr_fun but in your case that won’t work either1. So the way forward is to wrap std::max into a functor:

template <typename T>
struct max : std::binary_function<T, T, T> {
    T operator ()(T value, T min) const {
        return std::max(value, min);
    }
};

Usage:

std::transform(vec.begin(), vec.end(), vec.begin(), std::bind2nd(max<int>(), 5));

1 It appears as if std::bind1st(std::ptr_fun(&std::max<int>), 5) should work but unfortunately this template instantiation creates two identical operator() overloads, since std::max takes its arguments as const.

Upvotes: 2

Sebastian Redl
Sebastian Redl

Reputation: 71899

Why do the two existing answers replace the perfectly good std::max with identically implemented functions/functors with different names? std::max is perfectly fine; it's the way you use the old binders that's wrong.

You say you don't have C++11. Do you have Boost? Boost.Bind will do the job:

std::transform(vec.begin(), vec.end(), vec.begin(),
               boost::bind(&std::max<int>, _1, 5));

I can't remember what namespace the placeholder is in.

If you can't use Boost either, you need to keep in mind that the old binders need special nested types from their bound functor argument, and function pointers don't have those, which is why the ptr_fun helper exists:

std::transform(vec.begin(), vec.end(), vec.begin(),
               std::bind1st(std::ptr_fun(&std::max<int>), 5));

Upvotes: 0

MatthiasB
MatthiasB

Reputation: 1759

You can use std::replace_if instead of transform. This allows you to use a predefined comparsion functor like std::less or std::greater instead of std::max:

std::replace_if(vec.begin(),vec.end(),std::bind2nd(std::less<int>(),5),5);

Here is a working example.

Upvotes: 2

Related Questions