Algorithms are container agnostic. Otherwise we will have to implement each algorithm 7 times (vector,deque,list,set,map,multi_set,multi_map), actually even more - slist, string, rope, C++11 unordered_map, user-defined? Decision was made that algorithms will work with ranges: 1 2 3 4 5 6 7 8 ^ ^ | | defines range 3 4 5 6 b e range from b to e defines half-open interval [b,e), where b is included in the range and e is excluded. Algorithm function design: 1) first 2 arguments are always the range 2) return value - most informative for the given algorithm 3) if second range is required it is provided by begin iterator only and algorithm assumes the range is long enough min_element =========== min_element( b, e ) - no more arguments are required - ret value? - value of the minimum, OK but hides position - index, but only makes sense for array-based containers - pointer, better - iterator, pointing at the smallest element std::list lst; // ... init ... std::list::iterator it_min = std::min_element( lst.begin(), lst.end() ); std::cout << "Min val is " << *it_min << std::endl; std::list::iterator it_min_left = std::min_element( lst.begin(), it_min ); std::list::iterator it_min_right = std::min_element( ++it_min, lst.end() ); //-------------------------------------- std::set st; // ... init ... std::set::iterator it_min = std::min_element( st.begin(), st.end() ); // unfortunately works // use st.begin() instead (std::set is sorted!) find ==== find( b, e, ... - need value to be found - 3d argument - ret value? - value - silly - index, but only makes sense for array-based containers - iterator std::list lst; // ... init ... std::list::iterator it_pos = std::find( lst.begin(), lst.end(), 2 ); if ( it_pos == lst.end() ) { std::cout << "2 is not in the set\n"; } else { std::cout << "Found 2\n"; it_pos = std::find( ++it_pos, lst.end(), 2 ); if ( it_pos == lst.end() ) { std::cout << "2 is not in the set\n"; } else { std::cout << "Found 2\n"; it_pos = std::find( ++it_pos, lst.end(), 2 ); if ( it_pos == lst.end() ) { std::cout << "2 is not in the set\n"; } } //-------------------------------------- std::list lst; // ... init ... std::list::iterator it_pos = lst.begin(); while ( ( it_pos = std::find( it_pos, lst.end(), 2 ) ) != lst.end() ) { ++it_pos; std::cout << "Found 2\n"; } //-------------------------------------- std::set st; // ... init ... std::set::iterator it_min = std::find( st.begin(), st.end(), 2 ); // unfortunately works // use st.find( 2 ) instead (std::set is a BST !) count - count all elements in container that are equal to a given ===== exercise: try to guess signature and ret val type, do not google equal ===== equal( b, e, ... - need second range - begin only - ret value - bool (STL) - another possibility, iterator to the first non-equal position V V 1 2 3 4 1 2 3 4 5 ^ bool equal( it1, it1_e, it2 ); V V 1 2 3 4 1 2 3 6 5 ranges are equal ^ V V 1 2 2 4 1 2 3 6 5 ranges are NOT equal ^ V V 1 2 3 4 0 1 2 3 6 5 ranges are equal ^ V V 1 2 3 4 1 2 3 * <--- crash, see implementation of equal below: ^ template < typename Iter1, typename Iter2 > bool equal( Iter1 it1, Iter1 it1_e, Iter2 it2 ) { while( it1 != it1_e ) { if ( *it1 != *it2 ) return false; // *it2 will creash on 4th iteration ++it1; ++it2; } retrun true; } Use this - check sizes before calling equal: to make v = 1 2 3 lst = 1 2 3 4 to be equal: if ( v.size() < lst.size() ) { equal( v.begin(), v.end(), lst.begin() ); // smaller first } else { equal( lst.begin(), lst.end(), v.begin() ); // smaller first } to make 1 2 3 1 2 3 4 to be different if ( v.size() != lst.size() ) { return false; } else { return equal( lst.begin(), lst.end(), v.begin() ); } Algorithms taking user-defined code: ------------------------------------ int multiply_by_3_val( int i ) { return 3*i; } for_each -------- 1 2 3 4 5 std::for_each( v.begin(), v.end(), multiply_by_3_val ); 1 2 3 4 5 // nothing changed void multiply_by_3_ref( int & i ) { return i*=3; } 1 2 3 4 5 std::for_each( v.begin(), v.end(), multiply_by_3_ref ); 3 6 9 12 15 std::vector output; output.resize( v.size( ) ); // NOT reserve !!!!! std::transform( v.begin(), v.end(), output.begin(), multiply_by_3_val ); 1 2 3 4 5 3 6 9 12 15 std::transform( v.begin(), v.end(), v.begin(), Div2 ); v 1 2 3 4 5 changes to v 0 1 0 1 0 bool Div2( int i ) { return (i%2)==0; } // return true if even std::vector::iterator it_new_end = std::remove_if( v.begin(), v.end(), Div2 ); // was data actually deleted? note algorithm CANNOT delete elements from a range. Algorithms only has access to range, not container, but only container KNOWS HOW TO DELETE!!! +--------------------------------+ | 1 2 3 4 5 6 7 8 9 1 2 3 4 5 6 7| +--------------------------------+ ^ range ^ ^ +-------+ | | | +---------+ insert | Alg |---------+---------+ +-------|Container| delete +-------+ +---------+ etc 3 1 2 1 2 2 1 1 2 3 std::vector::iterator it_new_end = std::remove_if( v.begin(), v.end(), Div2 ); 3 1 1 1 1 3 2 2 2 2 ^ | ret val // remove will push all elements that should be deleted to the end // and will give you an iterator where they start, so that: v.erase( it_new_end, it_end ); or 1-liner v.erase( std::remove_if( v.begin(), v.end(), Div2 ), it_end ); v.erase( std::remove_if( std::find( it_pos, v.end(), 2 ), v.end(), Div2 ), it_end ); std::vector< std::string > v; // one two three four char global_char = 'a'; int global_counter = 0; ??? CC( std::string const& str ) { for( auto const& ch : str ) { global_counter += ((ch==global_char)?1:0); } } global_char = 'o'; global_counter = 0; std::for_each( v.begin(), v.end(), CC ); template < typename Iter1, typename Op > Op for_each( Iter1 b, Itre1 e, Op op ) { while( b != e ) { op( *b ); ++b; } return op; } class F { // functors public: int operator() () { return 2; } int operator() ( int i ) { return i*i; } int operator() ( int i, int j ) { return i*j; } int operator[] ( int i ) { return i*i; } }; F f; f( 5 ); f[ 5 ]; foo(6); class X { int counter = 0; char m_ch; pubcli: X( char _ch ) : m_ch(_ch) {} bool operator() ( std::string const& str ) { for( auto const& ch : str ) { counter += ((ch==m_ch)?1:0); } } int GetCount(); }; X x; x(2); x.GetCode(); X count_o = ( 'o' ); std::for_each( v.begin(), v.end(), count_o ); // for_each uses a copy of count_o to count count_o.GetCount(); // count=0 X count_e = ( 'e' ); std::for_each( v.begin(), v.end(), count_e ); // for_each uses a copy of count_e to count count_e.GetCount(); // count=0 X count_o = ( 'o' ); X rv = std::for_each( v.begin(), v.end(), count_o ); rv.GetCount(); // correct X rv = std::for_each( v.begin(), v.end(), X( 'o' ) ); rv.GetCount(); // correct std::for_each( v.begin(), v.end(), X( 'o' ) ).GetCount(); More examples: ============= Add 2 ranges: struct Sum { int operator() ( int const& a1, int const& a2 ) const { return a1+a2; } }; std::vector v1( 10 ); // init to 1,..,10 std::vector v2( 10 ); // init to 1,..,10 std::vector res( 10 ); std::transform( v1.begin(), v1.end(), v2.begin(), res.begin(), Sum() ); // ---- input 1 ---- --input2-- --output-- --operation Works as expected. -------------------------- std::vector v1( 10 ); // init to 1,..,10 std::list lst; // init to 1,..,10 std::vector res( 10 ); std::transform( v1.begin(), v1.end(), lst.begin(), res.begin(), Sum() ); -------------------------- std::vector v1( 10 ); // init to 1,..,10 std::list lst; // init to 1.1,2.2,... <<<<<------------ changed to double std::vector res( 10 ); <<<<<------------ changed to double std::transform( v1.begin(), v1.end(), lst.begin(), res.begin(), Sum() ); output is rounded -------------------------- template < typename T > struct Sum { T operator() ( T const& a1, T const& a2 ) const { return a1+a2; } }; std::vector v1( 10 ); // init to 1,..,10 std::list lst; // init to 1.1,2.2,... <<<<<------------ changed to double std::vector res( 10 ); <<<<<------------ changed to double std::transform( v1.begin(), v1.end(), lst.begin(), res.begin(), Sum() ); -------------------------- Good news - STL already has: plus() minus() multiplies() divides() and also many more (boolean logic operators, modulus, comparisons): std::transform( cont1.begin(), cont1.end(), // input 1 cont2.begin(), // input 2 cont3.begin(), std::plus() // unnamed temp object of type plus ); std::transform(cont1.begin(), cont1.end(), cont2.begin(), cont3.begin(), std::less()); std::transform(cont1.begin(), cont1.end(), cont2.begin(), cont3.begin(), std::logical_and()); // assume cont1 and cont2 are containers of booleans ... x ... y I can ... x+y ... x/y ... x*x + y*y // using std::compose ... x*x + y*y*y // only using lambda function -------------------------- Add 10 to each element of a container: std::vector v1( 10 ); // init to 1,..,10 std::transform( v1.begin(), v1.end(), v1.begin(), std::plus() ); --- input --- -- out -- -- operation is binary - does not compile std::transform( v1.begin(), v1.end(), v1.begin(), std::plus() + 10 ???? ); Solution, use adapter: std::transform( v1.begin(), v1.end(), v1.begin(), std::bind2nd( std::plus(), 10 ) ); std::plus() represents x + y std::bind2nd( std::plus(), 10 ) represents x + 10 std::bind1st( std::plus(), 10 ) represents 10 + y namespace std { template struct plus { T operator() ( T const& a1, T const& a2 ) { return a1+a2; } }; } std::transform( v1.begin(), v1.end(), v1.begin(), std::bind2nd( std::plus(), 10 ) ); auto rv = std::bind2nd( std::plus(), 10 ) 1) bind2nd - function, type (ctor call), not a value ( "5()" ) 2) bind2nd is it a template combining 1 and 2 it is a function 3) rv is user-defined type and it implements operator() template< typename T1, typename T2 > struct Bind2nd { T1 op; T2 arg2; ??? operator () ( arg1 ) { return op( arg1, arg2 ); } }; template< typename T1, typename T2 > bind2nd( T1 op, T2 arg2 ) { return Bind2nd( op, arg2 ); } See slides how to implement bind2nd by hand. Note: //C++11 lambda expressions: std::transform( v1.begin(), v1.end(), v1.begin(), [](int const& x){ return x+10; } ); -------------------------- int Power ( int b, int e ) { int res = 1; for ( int i=0; i v1( 10 ); // init to 1,..,10 std::transform( v1.begin(), v1.end(), v1.begin(), std::bind2nd( Power, 2 ) ); // does not compile Solution: std::transform( v1.begin(), v1.end(), v1.begin(), std::bind2nd( std::ptr_fun( Power ), 2 ) ); std::for_each (v.begin(), v.end(), &C::Square ); -- inside for each: op( *it ); op - member function ptr *it - object of type C should be (*it).*op(); -------------------------- See implement member function pointer adaptor slides ----------------------------- std::vector v1( 10 ); std::list lst; // size 0 // std::copy( v1.begin(), v1.end(), lst.begin() ); std::copy( v1.begin(), v1.end(), back_inserter( lst ) ); class back_inserter { std::list & lst; public: back_inserter( std::list & _lst ) : lst(_lst) { } // lst.push_back( ??? ); void operator++() { } void operator=( int i ) { lst.push_back( i ); } back_inserter& operator*() { return *this; } }; template OutputIt copy(InputIt first, InputIt last, OutputIt result) { while (first != last) { *result = *first; ++result; ++first; } return result; } -------------------------- See C++03 lambda expressions slides. Code: #include #include #include #include template < typename T > struct Sum { T operator() ( T const& a1, T const& a2 ) const { return a1+a2; } }; int Power ( int b, int e ) { int res = 1; for ( int i=0; i v1( 10 ); for ( int i=0; i<10; ++i) { v1[i] = i+1; } std::list lst; for ( int i=0; i<10; ++i) { lst.push_back( 1*(i+1) ); } std::vector res( 10 ); std::transform( v1.begin(), v1.end(), lst.begin(), res.begin(), Sum() ); for ( int i=0; i<10; ++i) { std::cout << v1[i] << " "; } std::cout << std::endl; std::copy( lst.begin(), lst.end(), std::ostream_iterator(std::cout) ); std::cout << std::endl; for ( int i=0; i<10; ++i) { std::cout << res[i] << " "; } std::cout << std::endl; std::transform( v1.begin(), v1.end(), v1.begin(), std::bind2nd( std::plus(), 10 ) ); for ( int i=0; i<10; ++i) { std::cout << v1[i] << " "; } std::cout << std::endl; //C++11 std::transform( v1.begin(), v1.end(), v1.begin(), [](int const& x){ return x+10; } ); for ( int i=0; i<10; ++i) { std::cout << v1[i] << " "; } std::cout << std::endl; //std::transform( v1.begin(), v1.end(), v1.begin(), std::bind2nd( Power, 2 ) ); // does not compile std::transform( v1.begin(), v1.end(), v1.begin(), std::bind2nd( std::ptr_fun( Power ), 2 ) ); for ( int i=0; i<10; ++i) { std::cout << v1[i] << " "; } std::cout << std::endl; } Added: template Op for_each(InputIt first, InputIt last, Op op) { while (first != last) { op(*first); // !!! inlined or not // function pointer cannot be inlined (since can change at runtime) // cRandomInt1::op() will be inlined (since cannot not change) ++first; } return op; } class By3 { public: int operator()(int x) // can be overloaded { return 3*x; } }; By3 op; int t = op(3); // t=9 foo(x); std::generate( ...., fRandomInt ); std::generate( ...., cRandomInt1() ); int fRandomInt(void) { return rand() % min + max-min; } class cRandomInt1 { int min; int max; public: cRandomInt1( int min, int max ) : min(min), max(max) {} int operator()(void) const { return rand() % 90 + 10; } }; std::generate( ...., cRandomInt1(0,100) ); // state element + element*element element*element Expression< Element, Element, Product> element + element*element Expression, Sum> auto sent1 = ( A > ( B & C | ~D ) );