I-16 questions about functors

The Partridge Family were neither partridges nor a family. Discuss.
Post Reply
MCanterel
Posts: 10
Joined: December 8th, 2017, 8:48 pm

I-16 questions about functors

Post by MCanterel » December 8th, 2017, 8:59 pm

Hey folks. Got a couple questions about function objects discussed in I-16.

1- This is from http://en.cppreference.com/w/cpp/algorithm/sort:

Code: Select all

// sort using a standard library compare function object
std::sort(s.begin(), s.end(), std::greater<int>());

for (auto a : s) {
	std::cout << a << " ";
}
std::cout << '\n';

// sort using a custom function object
struct {
	bool operator()(int a, int b) const
	{
		return a < b;
	}
} customLess;

std::sort(s.begin(), s.end(), customLess);  //NO PARENS (or braces) AFTER customLess ???
for (auto a : s) {
	std::cout << a << " ";
}
std::cout << '\n';
My question: Why are there no parens after custom function object call customLess, while they are there are after std lib call to std::greater?

2- Chili's implementation of a ThresholdTestY: I get that we're calling the class constructor in compare object by using the braces, but confused about how the () operator gets called when we type:

Code: Select all

const auto new_end = std::remove_if(vd.begin(), vd.end(), ThresholdTestY{ 20 });
3- I figured out I could instantiate a ThresholdTestY object and pass it to the sort function, but again, don't quite understand why we're not using parens....

Code: Select all

ThresholdTestY testY(20);
 const auto new_end = std::remove_if(vd.begin(), vd.end(), testY);
Thanks for any and all insights-- MC

albinopapa
Posts: 4373
Joined: February 28th, 2013, 3:23 am
Location: Oklahoma, United States

Re: I-16 questions about functors

Post by albinopapa » December 9th, 2017, 6:35 am

Code: Select all

    struct {
        bool operator()(int a, int b) const
        {   
            return a < b;
        }   
    } customLess;
If you notice, customLess isn't a template, so no need for <> angle brackets and you aren't calling the functor directly so no need to include parens...you are passing an object that has the operator() overloaded.

In this example, they create an unnamed struct and instantiate an instance with the name customLess.

#2:

Code: Select all

const auto new_end = std::remove_if(vd.begin(), vd.end(), ThresholdTestY{ 20 });
The braces are there to initialize a ThresholdTestY object that is getting passed to the remove_if function. Inside the remove_if function there is something like this:

Code: Select all

template<class iterator, class func>
iterator remove_if( iterator beg, iterator end, func fn)
{
     auto it = beg;
     auto next = it;
     ++next;
     for(; next != end; ++it, ++next)
     {
          if( Fn( *it ) )
               *it++ = std::move(next++);
     }
}
It's been awhile since I looked at the function, but this should be pretty close. Basically, what you pass at the end, if it's callable with () then it gets called inside the remove_if function, not at the callsite of remove_if, remember, it has to call this for each element in the range, beg -> end.

#3 Answered by #1 and #2.
As long as your structs or classes have a public operator() overloaded and the signature matches the data types that are in the container ( std::vector or std::list, etc...) then you can pass the object and the operator() will be called inside of these algorithms.
If you think paging some data from disk into RAM is slow, try paging it into a simian cerebrum over a pair of optical nerves. - gameprogrammingpatterns.com

MCanterel
Posts: 10
Joined: December 8th, 2017, 8:48 pm

Re: I-16 questions about functors

Post by MCanterel » December 10th, 2017, 12:03 am

it gets called inside the remove_if function, not at the callsite of remove_if
--that's what I needed to know. Thanks a!

Post Reply