This is a syntax question.
C++ STL sort function:
template <class RandomAccessIterator, class Compare>
void sort (RandomAccessIterator first, RandomAccessIterator last, Compare comp);
The documentation says that comp can be either a function pointer or an object.
But if you pass a function pointer, what mechanism of C++ allows the function pointer to be used in place of an object i.e. Compare comp?
Why isn't it a compile error?
Given an object with a function call operator,
struct Functor {
bool operator()(const Foo& a, const Foo& b) {
return a < b;
}
};
it is easy to see that the sort function can be instantiated such that the Compare comp parameter accepts a Functor object.
sort(/* other params we don't care about here */, Functor comp);
Fair enough.
Your question is - how can this accept a function pointer? Let's begin by examining what is the type of a function pointer?
Consider the following
bool compare(const Foo& a, const Foo& b);
bool (*func_ptr)(const Foo&, const Foo&) = compare;
The type of a pointer to the function compare, as shown in the second line above, is bool (*)(const Foo&, const Foo&). You can typedef this just as you can any other type:
typedef bool (*func_ptr_type)(const Foo&, const Foo&);
func_ptr_type ptr = compare;
Or equivalently:
using func_ptr_type = bool(*)(const Foo&, const Foo&);
func_ptr_type ptr = compare;
Now, when you provide a function pointer to std::sort, it should be obvious that the type Compare becomes the pointer type, analogous to func_ptr_type above, and the argument looks much the same as the example in the second line:
sort(/* other params we don't care about here */, func_ptr_type comp);
This all works because the sort function is actually a function template. It gets instantiated with different types based on its usage. When it's instantiated with an object, its parameter accepts that object by value (the Compare type is deduced to be the type of the object). When it's instantiated with a function pointer, the Compare type is deduced to be the function pointer type.
Related
The accepted answer I've seen for swapping out a priority queue comparator is to overload the operator in a new compare class.
class Foo
{
};
class Compare
{
public:
bool operator() (Foo, Foo)
{
return true;
}
};
int main()
{
std::priority_queue<Foo, std::vector<Foo>, Compare> pq;
return 0;
}
However, I want to implement several (10+) different compare functions for queue and choose one at run time when pq is created in main(). Do I have to make 10 different compare classes or is there an easier way to do this?
Do I have to make 10 different compare classes or is there an easier way to do this?
You don't have to. The priority_queue requires that the comparator taking a Foo and return bool - with the default one is std::less
template<
class T,
class Container = std::vector<T>,
class Compare = std::less<typename Container::value_type>
> class priority_queue;
In your case, you may use a lambda, or a pointer to function for that purpose. For example,
using cmp1 = bool(*)(const Foo&, const Foo&);
bool FooCmp1(const Foo& f1, const Foo& f2)
{
// do real comparison..
return true;
}
priority_queue<Foo, std::vector<Foo>, cmp1> pq(FooCmp1);
Use a function for comparer template argument, pass the instance of the function to the constructor of the queue, see second constructor there.
For the type, you can use C++ function object std::function<bool(const Foo& a, const Foo& b)>, or C function pointer i.e. bool(*)(const Foo& a, const Foo& b).
I have 2 overloaded function say - func1 and func2 -
Func1 is -
template<typename T1, typename T2> bool AreIdentical(const std::pair<T1, T2>
&lhs, const std::pair<T1, T2> &rhs)
{
//some code
}
Func2 is -
template<typename T> bool AreIdentical(typename std::map<int,
std::vector<T>>::iterator itOrig,
typename std::map<int, std::vector<T>>::iterator itNew)
{
//some code
}
I am trying to call the function AreIdentical in below manner -
int main()
{
std::map<int, std::vector<int>> orgitem;
std::map<int, std::vector<int>> newitem;
newitem[0];
orgitem[0];
AreIdentical(*orgitem.begin(), *newitem.begin());
return 0;
}
Now, interesting thing is, my origitem and newitem is of map type but always Func1 is getting called which takes parameter pair type instead of Func2.
Do anyone have any clue why is it happening so?
orgitem.begin() is an iterator. But *orgitem.begin() is the object the iterator points at, which is a std::pair<const int, std::vector<int>>.
If you had
AreIdentical(orgitem.begin(), newitem.begin());
without the dereferencing * operators, that would not be able to call the pair overload.
But in fact it won't work either, because in your second overload the parameter T is not in a deducible context. The only way to call it is:
AreIdentical<int>(orgitem.begin(), newitem.begin());
You might be able to "fix" this by changing the iterator overload to just accept any iterator whose value type has members first and second:
template <typename Iter>
auto AreIdentical(Iter itOrig, Iter itNew)
-> decltype((*itOrig).first, (*itOrig).second, bool{});
In an assignment I'm told to implement bool operator()(const T&, const T&) for some class. Overloading bool operator is meant to allow the object to be implicitly cast to bool. What does it mean to overload it with two parameters? How are these parameters passed on the calling side? How is this used?
That is not "operator bool", but operator(), with two T arguments, returning a bool. In other words, it is a binary predicate. You can use it like this:
struct Foo
{
bool operator()(const T&, const T&); // should probably be const
};
...
Foo f;
T t1, t2;
bool b = f(t1, t2);
You confuse operator bool with operator() with return type bool. The assignment is about the latter.
Say I have this declaration of a priority queue:
struct orderByRewards{
bool operator() (pair<int,pair<int,int> > a, pair<int, pair<int, int> > b){
return a.first < b.first;
}
};
priority_queue<pair<int,pair<int,int> >, vector<pair<int,pair<int,int> > >, orderByRewards> Q;
I was wondering if anybody could take their time and explain me how does the compiler interpret the compare class.
Why do I need to overload the () operator ?
Also, where's the () operator used in its comparing process ?
It feels a little weird, especially since I am not really comfortable with templates and all OOP concepts.
Why do we need to declare the type of a single object and the container type ?
You're essentially asking about function objects (or functors). A function object is one that overloads operator(). You can use such an object as though it were a function. The standard provides a few comparison functors (like your orderByRewards). For example, std::less looks something like this:
template <class T>
struct less {
constexpr bool operator()(const T &lhs, const T &rhs) const
{
return lhs < rhs;
}
};
As we can see, the overloaded operator() just compares the two arguments using < and then returns the boolean result. To use this, you need to create an object of type std::less and then use the function call syntax on it:
std::less<int> compare;
assert(compare(5, 7) == true);
Even though compare is an object, we were able to use it like a function in compare(5, 7).
So now we know that your type orderByRewards is a function object type. You are passing it as a template type argument of std::priority_queue. The implementation of std::priority_queue can then create objects of this comparison function object when it needs to compare elements within the queue.
Consider a simpler example:
template <typename T, typename Comp>
struct foo {
void bar(T a, T b) {
Comp compare;
if (compare(a, b)) {
std::cout << "True" << std::endl;
} else {
std::cout << "False" << std::endl;
}
}
};
It's a silly example, but it gets the point across. We can use this like so:
foo<int, std::less<int>> my_foo;
my_foo.bar(5, 7); // Will print true
We were able to configure foo, by passing it some arbitrary comparison functor type, that its member function bar was able to instantiate and use.
So in the same way, you are configuration std::priority_queue by giving it a comparison functor type that it can use to order elements within the queue. This is how it determines priority between elements. In fact, the default template type argument for std::priority_queue is std::less.
You are not required to overfload the operator(). You can declare your custom method:
typedef bool (*comp)(int,int);
bool compare(int a, int b)
{
return (a<b);
}
int main()
{
std::priority_queue<int,std::vector<int>, comp> pq(compare);
return 0;
}
Updated:
As #WhozCraig pointed out:
It is possible to use this object without overloading the operator() but the compiler will face an easier situation inlining operator() comparison function rather than runtime-provided dereferenced comparison function
Perhaps it would make the most sense to look at the definition of std::priority_queue and work from there.
template <class T, class Container = vector<T>,
class Compare = less<typename Container::value_type> >
class priority_queue {
This says that Compare is some type, and defaults to std::less<T>, for T = the value_type of the underlying container. This compensates for the possibility that you might do something slightly insane like creating a priority_queue of one type, but have the underlying container hold another type (though that's not particularly likely, except by accident).
std::less, in turn, is defined like this:
template <class T> struct less {
bool operator()(const T& x, const T& y) const;
// plus a few typedefs for the argument and return types.
};
In short, it's a type defined with only one publicly available operation: an operator() that can be passed two items that it compares, and returns a bool to indicate whether the first is less than the second.
Since that's what std::priority_queue expects to use, whatever you provide must support essentially the same function call-like syntax and semantics (e.g., the operator() should take const arguments and should itself be const-qualified).
A std::map must satisfy the requirements of an associative container specified in paragraph 23.1.2/2:
Each associative container is
parameterized on Key and an ordering
relation Compare that induces a strict
weak ordering (25.3) on elements of
Key. In addition, map and multimap
associate an arbitrary type T with the
Key. The object of type Compare is
called the comparison object of a
container. This comparison object may
be a pointer to function or an object
of a type with an appropriate function
call operator.
But then in paragraph 23.3.1/2 the std::map template is specified as:
template <class Key, class T, class Compare = less<Key>,
class Allocator = allocator<pair<const Key, T> > >
class map;
which seems to explicitly prohibit the use of a function pointer as Compare. Is this a contradiction or am I not understanding the standard correctly?
EDIT: Yes, the problem I was really having was why code like GMan's example:
struct foo
{
int x;
};
bool compare_foo(const foo& x, const foo& y)
{
return x.x < y.x;
}
std::map<foo, bool, compare_foo> fooMap;
wouldn't compile (yeah, I stupidly mixed up the type and value of the Compare parameter).
Compare is the type of the comparator. The fact that it is declared with class instead of typename doesn't make a difference, you can have a pointer to function as type and give your function in the map constructor.
#include <map>
bool myCmp(int a, int b) {
return a < b;
}
void foo()
{
std::map<int, char*, bool (*)(int, int)> m(myCmp);
}
This:
class Compare
does not mean that Compare has to be a class. It might be clearer if it said:
typename Compare
You can use any type that provides the comparable function call semantics, such as a function pointer.
Specify it like this:
struct foo
{
int x;
};
bool compare_foo(foo x, foo y)
{
return x.x < y.x;
}
// vvvvvvvvvvvvvvvvv function pointer type
std::map<foo, bool, bool(*)(foo, foo)> fooMap(compare_foo);
// function pointer value ^^^^^^^^^^^
You are confusing the type and the value of the comparator; use this e.g.:
int main()
{
std::map<foo, bool, bool(*)(const foo&, const foo&)> fooMap(compare_foo);
}