Contradiction in C++ standard? - c++

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);
}

Related

C++ What's the best way to implement a Priority Queue with varying priority functions?

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).

STL sort function with comparator

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.

c++ - Priority Queue - How does it work internally?

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).

Utilizing comparison function fails with reference types

I have a templated class which looks as follows (assume a using namespace std for brevity):
template <typename Type, typename Compare = less<Type>>
struct weighted_base
{
typedef typename set<pair<Type, double>, set_compare<Type, Compare>> mapped_type;
map<Type, mapped_type, Compare> backing_map;
...
};
where set_compare is defined as:
template <typename Type, typename Compare>
struct set_compare
{
bool operator()(const pair<Type, double>& a,
const pair<Type, double>& b)
{
return Compare(a.first, b.first);
}
};
That is, the map takes keys of type Type to std::set<std::pair<Type, double>> values. This has some problems when I use a method such as:
void insert(const Type& from, const Type& to, double weight)
{
//...
mapped_type& adj_nodes = backing_map[from];
adj_nodes.insert(make_pair(to, weight));
}
The problem is that within the set, when it goes to call set_compare, it has a type of const Type&, not Type. Thus, assuming it's std::less, in this case it will be trying to call less<int>::less(const int& a, const int& b) which fails.
Is there some way of fixing it so that both contains can use (effectively) the same comparison function here?
Compare is the type of a binary functor, so you probably need
return Compare()(a.first, b.first);
where Compare() is a temporary, defualt constructed, Compare instance. For example, if you substitute Compare for std::less<int>,
std::cout << std::boolalpha;
std::cout << std::less<int>(5,50) << "\n"; // Error!
std::cout << std::less<int>()(5,50) << "\n"; // OK
Your error is likely to give you many compiler errors, some of which could send you down the wrong track. I suggest fixing it first, then seeing if the code behaves as you expect it to.

How can I find an element in a set which contains pointers to the elements?

Edit: I fixed my mistake: I'm using a set and not a vector.
Please consider the following example code:
set<Foo *> set_of_foos;
set_of_foos.insert(new Foo(new Bar("x")));
set_of_foos.insert(new Foo(new Bar("y")));
[...]
// The way a "foo" is found is not important for the example.
bool find_foo(Foo *foo) {
return set_of_foos.end() != set_of_foos.find(foo);
}
Now when I call:
find_foo(new Foo(new Bar("x")));
the function returns false since what I'm looking for can't be found. The reason is obvious to me: The pointers point to different objects since they are allocated both with a new, resulting in different values of the addresses.
But I want to compare the contents of Foo (i.e. "x" in the above example) and not Foo * itself. Using Boost is not an option as well as modifying Foo.
Do I need to loop through each of the Foo * inside set_of_foos or is there a simpler solution? I tried uniquely serializing the contents of each Foo and replace the set<Foo *> with a map<string, Foo *>, but this seems like a very "hacked" solution and not very efficient.
Change your vector to set with your custom comparable function to compare Foo objects.
Should be:
struct ltFoo
{
bool operator()(Foo* f, Foo* s) const
{
return f->value() < s->value();
}
};
set<Foo*, ltFoo> sFoo;
sFoo.insert(new Foo(new Bar("x"));
sFoo.insert(new Foo(new Bar("y"));
if (sFoo.find(new Foo(new Bar("y")) != sFoo.end())
{
//exists
}
else
{
//not exists
}
find_foo(new Foo(new Bar("x"))); does not sound like a good idea - it will most likely (in any scenario) lead to memory leak with that search function.
You could use find_if with a functor:
struct comparator {
Foo* local;
comparator(Foo* local_): local(local_) {}
~comparator() { /* do delete if needed */ }
bool operator()(const Foo* other) { /* compare local with other */ }
};
bool found = vec.end() != std::find_if(vec.begin(), vec.end(), comparator(new Foo(...)));
Do I need to loop through each of the Foo * inside vector_of_foos or is there a simpler solution?
You do need to loop to find what you want, but you can use std::find_if or another "wrapped loop". This is more natural with lambdas in C++0x, but in C++03 I'd just use a regular for loop, possibly wrapped in your own function if you need to do this in more than one place.
Instead of using std::find, use std::find_if and provide your own predicate. This of course relies in you being able to access the member that holds "x" in Foo.
struct FooBar
{
FooBar(Foo* search) : _search(search){}
bool operator(const Foo* ptr)
{
return ptr->{access to member} == _search->{access to member};
}
Foo* _search;
}
vector<Foo*>::iterator it = std::find_if(vec.begin(), vec.end(), FooBar(new Foo(new Bar("x")));
If you can't access the member and you can guarantee that all other members will be the same, you could try a bare memcmp in the above functor rather than "==".
You may consider also using the Boost Ptr container library. It allows having a list of pointers using standard algorithms, find, etc. as if it contained objects, and automatically releasing the memory used by the pointers upon vector deletion.
I had the same question and ended up writing a simple DereferenceCompare class to do the job. I'd be curious to know what others think of this. At the crux of the problem is that the existing answers require the programmer using your set to access it in an unusual way that is prone to leaking memory, i.e. by passing an address of a temporary to std::set::find() or through std::find_if(). What's the point of using a standard container if you're going to access it in a non-standard way? Boost has a good container library that solves this problem. But since transparent comparators were introduced in C++14 you can write a custom comparator that makes std::set::insert() and std::set:find() work as expected without depending on Boost. You could use it as something like std::set< Foo*, DereferenceCompare<Foo, YourFooComparator> > set_of_foos;
#ifndef DereferenceCompare_H
#define DereferenceCompare_H
#include <type_traits>
// Comparator for std containers that dereferences pointer-like arguments.
// Useful for containers of pointers, smart pointers, etc. that require a comparator.
// For example:
// std::set< int*, DereferenceCompare<int> > myset1;
// int myint = 42;
// myset1.insert(&myint);
// myset1.find(&myint) == myset.end(); // false
// myset1.find(myint) == myset.end(); // false
// myset1.find(42) == myset.end(); // false
// myset1.find(24) == myset.end(); // true, 24 is not in the set
// std::set<int*> myset2;
// myset2.insert(&myint); // compiles, but the set will be ordered according to the address of myint rather than its value
// myset2.find(&myint) == myset.end(); // false
// myset2.find(a) == myset.end(); // compilation error
// myset2.find(42) == myset.end(); // compilation error
//
// You can pass a custom comparator as a template argument. It defaults to std::less<T>.
// The type of the custom comparator is accessible as DereferenceCompare::compare.
// For example:
// struct MyStruct { int val; };
// struct MyStructCompare { bool operator() (const MyStruct &lhs, const MyStruct &rhs) const { return lhs.val < rhs.val; } };
// std::set< MyStruct*, DereferenceCompare<MyStruct, MyStructCompare> > myset;
// decltype(myset)::key_compare::compare comparator; // comparator has type MyStructCompare
template< typename T, class Compare = std::less<T> > class DereferenceCompare
{
#if __cplusplus==201402L // C++14
private:
// Less elegant implementation, works with C+=14 and later.
template<typename U> static constexpr auto is_valid_pointer(int) -> decltype(*(std::declval<U>()), bool()) { return std::is_base_of<T, typename std::pointer_traits<U>::element_type>::value || std::is_convertible<typename std::remove_cv<typename std::pointer_traits<U>::element_type>::type, T>::value; }
template<typename U> static constexpr bool is_valid_pointer(...) { return false; }
public:
template<typename U, typename V> typename std::enable_if<is_valid_pointer<U>(0) && is_valid_pointer<V>(0), bool>::type operator() (const U& lhs_ptr, const V& rhs_ptr) const { return _comparator(*lhs_ptr, *rhs_ptr); } // dereference both arguments before comparison
template<typename U, typename V> typename std::enable_if<is_valid_pointer<U>(0) && !is_valid_pointer<V>(0), bool>::type operator() (const U& lhs_ptr, const V& rhs) const { return _comparator(*lhs_ptr, rhs); } // dereference the left hand argument before comparison
template<typename U, typename V> typename std::enable_if<!is_valid_pointer<U>(0) && is_valid_pointer<V>(0), bool>::type operator() (const U& lhs, const V& rhs_ptr) const { return _comparator(lhs, *rhs_ptr); } // dereference the right hand argument before comparison
#elif __cplusplus>201402L // Better implementation, depends on void_t in C++17.
public:
// SFINAE type inherits from std::true_type if its template argument U can be dereferenced, std::false otherwise.
// Its ::value member is true if the type obtained by dereferencing U, i.e. the pointee, is either derived from T or convertible to T.
// Its ::value is false if U cannot be dereferenced, or it the pointee is neither derived from nor convertible to T.
// Example:
// DereferenceCompare<int>::has_dereference; // std::false_type, int cannot be dereferenced
// DereferenceCompare<int>::has_dereference<int>::is_valid_pointee; // false, int cannot be dereferenced
// DereferenceCompare<int>::has_dereference<int*>; // std::true_type, int* can be dereferenced to int
// DereferenceCompare<int>::has_dereference<int*>::is_valid_pointee; // true, dereferencing int* yields int, which is convertible (in fact, the same type as) int
// DereferenceCompare<int>::has_dereference< std::shared_ptr<int> >::is_valid_pointee; // true, the pattern also works with smart pointers
// DereferenceCompare<int>::has_dereference<double*>::is_valid_pointee; // true, double is convertible to int
// struct Base { }; struct Derived : Base { }; DereferenceCompare<Base>::has_dereference<Derived*>::is_valid_pointee; // true, Derived is derived from Base
// DereferenceCompare<int>::has_dereference<Derived*>; // std::true_type, Derived* can be dereferenced to Derived
// DereferenceCompare<int>::has_dereference<Derived*>::is_valid_pointee; // false, cannot convert from Derived to int nor does Derived inherit from int
template< typename, class = std::void_t<> > struct has_dereference : std::false_type { static constexpr bool is_valid_pointee = false; };
template< typename U > struct has_dereference< U, std::void_t<decltype(*(std::declval<U>()))> > : std::true_type { static constexpr bool is_valid_pointee = std::is_base_of<T, typename std::pointer_traits<U>::element_type>::value || std::is_convertible<typename std::remove_cv<typename std::pointer_traits<U>::element_type>::type, T>::value; };
template<typename U, typename V> typename std::enable_if<has_dereference<U>::is_valid_pointee && has_dereference<V>::is_valid_pointee, bool>::type operator() (const U& lhs_ptr, const V& rhs_ptr) const { return _comparator(*lhs_ptr, *rhs_ptr); } // dereference both arguments before comparison
template<typename U, typename V> typename std::enable_if<has_dereference<U>::is_valid_pointee && !has_dereference<V>::is_valid_pointee, bool>::type operator() (const U& lhs_ptr, const V& rhs) const { return _comparator(*lhs_ptr, rhs); } // dereference the left hand argument before comparison
template<typename U, typename V> typename std::enable_if<!has_dereference<U>::is_valid_pointee && has_dereference<V>::is_valid_pointee, bool>::type operator() (const U& lhs, const V& rhs_ptr) const { return _comparator(lhs, *rhs_ptr); } // dereference the right hand argument before comparison
#endif
public:
typedef /* unspecified --> */ int /* <-- unspecified */ is_transparent; // declaration required to enable polymorphic comparisons in std containers
typedef Compare compare; // type of comparator used on dereferenced arguments
private:
Compare _comparator;
};
#endif // DereferenceCompare_H
C++11
If you can make use of C++11 features, then you can also use a lambda expression instead of defining a comparison object,
as shown in the other answers. To make the below example code working, I have defined Bar and Foo from your code as follows:
struct Bar {
Bar(std::string s) : str(s) {}
std::string str;
};
struct Foo {
Foo(Bar* p) : pBar(p) {}
Bar* pBar;
};
If you provide the below lambda expression as key comparison function to the std::set,
then your content (i.e. the strings "x" and "y") is compared instead of the pointers pointing to the content.
Consequently, also the find() works as intended, as shown by the following code:
int main() {
auto comp = [](const Foo* f1, const Foo* f2) { return f1->pBar->str < f2->pBar->str; };
std::set<Foo*, decltype(comp)> set_of_foos(comp);
set_of_foos.emplace(new Foo(new Bar("x")));
set_of_foos.emplace(new Foo(new Bar("y")));
auto it = set_of_foos.find(new Foo(new Bar("x")));
if (it == std::end(set_of_foos))
std::cout << "Element not found!" << std::endl;
else
std::cout << "Element found: " << (*it)->pBar->str << std::endl;
return 0;
}
Output:
Element found: x
Code on Ideone
Note: A std::set only allows unique entries (i.e. keys). Whether entries are unique is decided based on the provided key comparison function.
For the code above this means, that you can only store a single entry with pBar->str == "x", even if Bar or Foo are stored at different adresses.
If you want to store multiple entries with pBar->str == "x" (for example), then you have to use a std::multiset.