Thread: Functors in Standard Library

  1. #1
    Registered User linuxdude's Avatar
    Join Date
    Mar 2003
    Location
    Louisiana
    Posts
    926

    Functors in Standard Library

    I have been programming with the STL for a while now and I have a question about using functors. Look at this code
    Code:
    #include <iostream>
    #include <vector>
    #include <algorithm>
    
    using namespace std;
    
    struct plus : public binary_function<int, int, int> {
       int operator() (int x, int y) { return x + y; }
    };
    
    void my_print(int x) {
       cout << x << endl;
    }
    
    int main(void)
    {
       vector<int> v(5);
       vector<int> w(5);
       vector<int> x(5);
       fill(v.begin(),v.end(), 5);
       fill(w.begin(),w.end(), 1);
       transform(v.begin(),v.end(), w.begin(), x.begin(), ::plus());
       for_each(x.begin(), x.end(), my_print);
       return 0;
    }
    Note how I use :: plus which is an object that overrides () and then I use my_print which is a function. I understand that they both do the same thing (:: plus() calls overloaded () operator and my_print is a function pointer) I was wondering why the STL uses classes and inheritance (i.e. inheriting from binary_function<arg1,arg2, retval>). Is this so you can store more information in a function like member variables? Also, is there any difference in performance between the two ways I used STL functions?

  2. #2
    The larch
    Join Date
    May 2006
    Posts
    3,573
    binary_function looks simply like this:

    Code:
    template<class Arg1, class Arg2, class Result>
        struct binary_function {
        typedef Arg1 first_argument_type;
        typedef Arg2 second_argument_type;
        typedef Result result_type;
        };
    By inheriting from that you make these typedefs available for your functor. These are used in some places: given a functor how would you determine what its return type is?

    Code:
    template <class Container, class Predicate>
    void foo(const Container& c, Predicate p)
    {
         //how do I know what types it takes and what type it returns?
         typename Predicate::result_type result = p(c[0], c[1]);
    }
    It's not necessary always but sometimes it might be useful.

    Same applies for writing your own iterators.
    I might be wrong.

    Thank you, anon. You sure know how to recognize different types of trees from quite a long way away.
    Quoted more than 1000 times (I hope).

  3. #3
    and the hat of sweating
    Join Date
    Aug 2007
    Location
    Toronto, ON
    Posts
    3,545
    Quote Originally Posted by linuxdude View Post
    Is this so you can store more information in a function like member variables?
    No. Any predicates you pass to STL containers/algorithms must be stateless, otherwise the behavior could be undefined.
    See: Chapter 87. Make predicates pure functions
    "I am probably the laziest programmer on the planet, a fact with which anyone who has ever seen my code will agree." - esbo, 11/15/2008

    "the internet is a scary place to be thats why i dont use it much." - billet, 03/17/2010

  4. #4
    Officially An Architect brewbuck's Avatar
    Join Date
    Mar 2007
    Location
    Portland, OR
    Posts
    7,396
    Quote Originally Posted by cpjust View Post
    No. Any predicates you pass to STL containers/algorithms must be stateless, otherwise the behavior could be undefined.
    See: Chapter 87. Make predicates pure functions
    Being "stateless" in this case just means that it always returns the same output for the same input. If the functor adheres to that, it can certainly take into account the values of some member variables.

    For instance, say you are using std::transform() to multiply all the elements of a vector by 2.7. You create a Multiply functor class, and construct it with an initializer of 2.7 which tells it what it needs to multiply by.

    The link cpjust provides is simply saying that this internal state should never change, i.e. if you pass value X to the functor and get result Y, then you should ALWAYS get result Y when you pass value X. That does not mean that the result can't depend on some state carried inside the functor.
    Code:
    //try
    //{
    	if (a) do { f( b); } while(1);
    	else   do { f(!b); } while(1);
    //}

  5. #5
    Registered User
    Join Date
    Jan 2007
    Posts
    330
    it is good practice to do this. Mostly to make your functors adaptable for use with std::bind1st, std::not1 and all the otrher adapters.

    See "Adaptable functions" here:

    http://www.builderau.com.au/program/...0278834,00.htm

    but scott meyers explains it better in:
    Effective STL: 50 Specific Ways to Improve the Use of the Standard Template Library Addison-Wesley Professional Computing Series: Amazon.co.uk: Scott Meyers: Books

  6. #6
    Registered User linuxdude's Avatar
    Join Date
    Mar 2003
    Location
    Louisiana
    Posts
    926
    Thanks for the information. These responses confirmed my thoughts. The "effective" books are so darn...effective. I don't have that one though. I'll have to look into it.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Program without standard library?
    By Sly in forum C Programming
    Replies: 23
    Last Post: 11-29-2008, 06:47 PM
  2. Writing your own C++ Standard Library implementation...
    By SlyMaelstrom in forum A Brief History of Cprogramming.com
    Replies: 20
    Last Post: 10-02-2006, 07:54 PM
  3. Standard C library Question
    By invisibleghost in forum C++ Programming
    Replies: 3
    Last Post: 10-24-2004, 01:40 PM
  4. Replies: 3
    Last Post: 09-04-2002, 09:01 PM
  5. C Standard Library
    By JoshG in forum C Programming
    Replies: 2
    Last Post: 07-17-2002, 09:09 AM