Sort vector of objects for binary search - c++

I have the following class:
struct EdgeExtended {
int neighborNodeId;
int weight;
int arrayPointer;
bool isCrossEdge;
};
I want to have a vector of such objects, sort it by neighborNodeId. Then I want to search for a particular neighborNodeId and return a reference to the found object inside the vector by binary search. Previously I used a map for that, so it was something like that:
map<int, EdgeExtended> neighbours;
.....
auto it = neighbours.find(dnodeId);
if (it != neighbours.end()) {
edgeMap = it->second;
}
Instead of
map<int, EdgeExtended> neighbours;
I want to have
vector<EdgeExtended> neighbours;
and retain as much as the old code the same.
I want to benchmark if the vector is faster than the map, since I am building thousands of vectors(or maps) and each vector (map) is relatively small (~10 items). I do not know how to a) make objects sortable by neighborNodeId and b) how to use binary search that searches for a particular member of the class (neighborNodeId). Sorry for the noob question. I am counting on your help.

You need a custom comparator function that takes two EdgeExtended objects and compares the fields you're interested in and that you can pass to both sort and binary_search as a third or fourth argument, respectively.
It can be conveniently done with a lambda function:
auto Comp = [](const EdgeExtended& e1, const EdgeExtended& e2)
{
return e1.neighborNodeId < e2.neighborNodeId;
};
If you stuck pre-C++11, write a class with overloaded operator() instead:
struct Comp {
bool operator()(const EdgeExtended& e1, const EdgeExtended& e2) const
{
return e1.neighborNodeId < e2.neighborNodeId;
}
};

Extending on jrok's answer, if you encounter similar problems more often, a reusable templated comparator which uses any member of a class comes in very handy.
template<class T, class U>
class CompareByMember {
U (T::*mem); // ugly syntax for member pointer of type U in class T
public:
CompareByMember(U (T::*mem)) : mem(mem) {}
bool operator()(const T &a, const T &b) {
return (a.*mem) < (b.*mem); // ugly syntax for member pointer access
}
};
As you can see, the syntax for pointers to class members is pretty strange, but once wrapped in this functor you don't have to care about it. One remaining "issue" is that you'd have to write the template parameters <T, U> each time you want to use this functor. But using type deduction this problem is solved, introducing a little helper function (note that its name is lower case):
template<class T, class U>
CompareByMember<T,U> compareByMember(U (T::*mem)) {
return CompareByMember<T,U>(mem);
}
This results in client code like this:
std::vector<EdgeExtended> v = ...;
std::sort(v.begin(), v.end(), compareByMember(&EdgeExtended::neighborNodeId));
Simple demonstration
For member functions, a similar templated functor can be written, using the only slightly different member function pointer syntax. You can also overload the call operator in the functor to accept raw pointers of T as well as any smart pointer wrapping around T* (using templates again).

Related

Writing a multi-dimensional "MathFunction"class by using C++11 variadic templates

I'd like to write a C++11 class that mimics the behavior of a mathematical function. The class takes as an input the sets upon which the function is defined, and it is possible to set and get the value associated with a specific point in the domain.
Since the number of sets that comprise the function domain is not know a priori, I'd like to use C++11 variadic templates to define the class as follows:
template<typename first_set_type, typename... additional_sets_type> class Function;
So that a new function can be created as follows:
Function<int, std::string, double> three_dim_function(S1, S2, S3);
where S1, S2 and S3 are std::set<int>, std::set<std::string> and std::set<double>, respectively. Setting and getting a value should resemble what happens with std::tuple:
three_dim_function.set<1, "a", 1.23>(12);
double twelve = three_dim_function.get<1, "a", 1.23>();
Most probably, std::unordered_map is the ideal data member to store the binding between domain and codomain:
std::unordered_map<std::tuple<first_set_type, additional_set_types...>, double> data_;
I tried to adapt the code from Initialzing and accessing members of a variadic class template, even though the two problems are not identical (in my case I may not need to store each single std::set).
EDIT #1: I'll try to better stress the issue I'm facing. In the linked question, the class is created by means of recursive calls. However, in my case I'm having troubles in understanding how to implement the constructor, i.e., how to set the domain of the function starting from the input sets. One possible way would be to use the constructor to pre-fill all the keys generated by the Cartesian product of the input sets for the data_ data member. The problem is that I don't know how to iterate over the parameter pack.
Tentative solution #1
Here's a tentative implementation: pastebin.com/FMRzc4DZ based on the contribution of #robert-mason. Unfortunately, it does not compile (clang 4.1, OSX 10.8.4) as soon as is_in_domain() is called. However, at first sight everything seems fine. What could be wrong?
I'm leaving my original answer below, but I'll try to address your question with variadic templates.
With a variadic function template, you do not iterate over the parameter pack. You must instead use a recursive function.
What I would use then would be something like:
template <class FirstDomain, class ...Domains>
class Function {
public:
typedef std::tuple<FirstDomain, Domains...> domain_t;
static constexpr size_t dimension = sizeof...(Domains) + 1; //+1 for FirstDomain
private:
std::tuple<std::set<FirstDomain>, std::set<Domains>...> domain;
std::unordered_map<domain_t, double> map;
template <size_t index = 0>
typename std::enable_if<(index < dimension), bool>::type
is_in_domain(const domain_t& t) const {
const auto& set = std::get<index>(domain);
if (set.find(std::get<index>(t)) != set.end()) {
return is_in_domain<index + 1>(t);
}
return false;
}
template <size_t index = 0>
typename std::enable_if<!(index < dimension), bool>::type
is_in_domain(const domain_t& t) const {
return true;
}
public:
Function(std::set<FirstDomain> f, std::set<Domains>... ds) :
: domain(f, ds...) {}
};
The trick is the combination of recursion and SFINAE. We need std::enable_if<> to prevent the compiler from expanding the calls to std::get<>(), as the index checking for get is done statically and will cause a compile error even if it will never be executed.
Possible areas of improvement would be making construction more efficient by moving the sets if you can. This would require perfect forwarding and other template magic, since you'd have to let template argument deduction deduce the types so that reference collapsing kicks in and then use a static_assert() to error when the deduced type is not the expected type (i.e. !(std::is_same<T, std::remove_cv<std::remove_reference<FirstDomain>::type>::type>::value), but in variadic form) and then forwarding to the set with std::forward().
(original answer)
In this case, you don't want to use the parameters as template arguments. There are all sorts of rules concerning template arguments that you don't want to have to deal with - specifically that all of the arguments have to be integral constant expressions.
You just want to use "normal" arguments, so that you can easily pass them in to the std::unordered_map, can be of any type, and can be runtime-defined:
I would recommend something like:
three_dim_function.set(1, "a", 1.23, 12);
double twelve = three_dim_function.get(1, "a", 1.23);
You can do some syntactic sugar if you like to make this look nicer:
template <class first_type, class ...addl_types>
class Function {
public:
//...
//left as an exercise for the reader
void set(std::tuple<first_type, addl_types...>, double);
class set_proxy {
friend class Function<first_type, addl_types...>;
std::tuple<first_type, addl_types...> input;
Function<first_type, addl_types...>& parent;
set_proxy(std::tuple<first_type, addl_types...> t, Function<first_type, addl_types...>& f)
: input(t), parent(f) {}
set_proxy(const set_proxy&) = delete;
set_proxy& operator=(const set_proxy&) = delete;
public:
//yes, I know this isn't the right return type, but I'm not sure what's idiomatic
void operator=(double d) {
parent.set(input, d);
}
};
set_proxy set(first_type f, addl_types... addl) {
return set_proxy{std::make_tuple(f, addl...), *this};
}
};
Which lets you then do:
Function<int, std::string, double> three_dim_function;
three_dim_function.set(1, "a", 1.23) = 12;

C++: use own class in a multiset container

at first I'm new here and English isn't my native language so apologize for any grammatical failures but I find this community really nice so I will try to ask my question as precise as I can.
I want to add my own class object into a stl container multiset and want to sort it with my own overloaded less operator defined in my class. I really tried out several solutions but nothing really worked so I hope someone can give me some useful hints to solve it.
Here is my general idea of my class definition:
class object {
public:
int first;
string second;
object(int f, string s) {
first = f;
second = s;
}
bool operator<(const object &comp) {
return first < comp.first;
}
};
This was my first try and it didn't work so I also tried out to declare the overloaded operator as a friend method but it didn't work also.
Here is a short code extract from my main function:
includes ...
//code omitted
int main() {
multiset<object*> mmset;
mmset.insert(new object(10, "test"));
mmset.insert(new object(11, "test"));
return 0;
}
After a while I started to debugging my code and try to figure out where the problem is and I come across the following thing that have made me a bit suspicious.
code extract from the stl:
// TEMPLATE STRUCT less
template<class _Ty>
struct less : public binary_function<_Ty, _Ty, bool>
{ // functor for operator<
bool operator()(const _Ty& _Left, const _Ty& _Right) const
{ // apply operator< to operands
return (_Left < _Right);
}
};
I have set a breakpoint on this line and observed what the program is doing here and I don't know why, but it only compares the addresses from the two objects and return so always false. It never calls my overloaded less operator although the operator exists and the _Left and _Right variables contain the address to my object.
I would really appreciate it if someone could help me.
Best Greetings
Tom
You are not storing objects in your multiset. You are storing object*s. These are pointers to objects. This means the set will order the pointers that you're inserting into it.
It seems like you really just want a multiset<object>:
multiset<object> mmset;
mmset.emplace(10, "test");
mmset.emplace(11, "test");
Now it will use < to compare the objects themselves.
If you really want to store pointers, you'll need to provide a custom comparator to the multiset. In C++11, you can do this easily with a lambda:
auto f = [](int* a, int* b) { return *a < *b; };
std::multiset<int*, decltype(f)> mmset(f);
Pre-C++11, you can create a function object that implements operator() with the same body as this lambda function.
Thank you for your help. That's seems to be a good solution to solve this problem.
I have searched a bit deeper in the new C++11 standard and found out that there is another possible solution to solve this with a little bit simpler implementation but the same result :)
I will post it just as information for other seekers with the same problem.
You can pass any constructor a stl container a so-called comparison object which the container will use to arrange your content.
The only thing you have to do is to define the overloaded operator() in your class and "misuse" them as a comparison operator.
class object {
int first;
string second;
object() { };
object(int f, string s) {
first = f;
second = s;
}
bool operator()(const object *comp1, const object *comp2) const {
return comp1->first < comp2->first;
}
}
The other thing what you have additionally to do now is to pass the object as the second argument in your definition of the container:
multiset(object*, object) mmset;
You can also use an extra class for this purpose just for comparison because otherwise you need a default constructor to use this class in this way.

Generic way to create comparer for objects behind pointers

I use data structures, and I sort these data structures a lot. These data structures are holding pointers to objects, not directly the objects themselves. Now I can write a simple comparison functor, or function, to tell the sort algorithm how to sort the pointers:
struct Object_ptr_comparer {
bool operator()(const Object* first, const Object* second) {
return *first < *second;
}
};
And use for example std::sort:
Object_ptr_comparer comp;
std::sort(data_str.begin(), data_str.end(), comp);
The only problem with this solution that I have to write extra pointer comparator functor for any type of class. Yes, I could use inheritance and polymorphism to write only the comparator of some root class, but I don't want to. Is there any other smart way to do this?
What about a template?
struct ptr_comparer {
template<typename T>
bool operator()(const T* first, const T* second) {
return *first < *second;
}
};
used like this:
std::sort(data_str.begin(), data_str.end(), ptr_comparer());
That's what templates are for!
struct ptr_comparer {
template<class Object>
bool operator()(const Object* first, const Object* second) const {
return std::less<Object>()(*first, *second);
}
};
std::sort(data_str.begin(), data_str.end(), ptr_comparer());
Since I've templated the operator rather than specializing the comparer directly, the compiler can deduce the types, so we don't have to put the types directly.
I use std::less rather than operator<, because it safely compares pointers to pointers (like char**), rather than relying on Undefined Behavior. std::less falls back on operator<, so it doesn't add any complexity to calling code, and there should be no downside.
I'm certain this one compiles

c++ sort class with class vector inside

I have a class cl1:
class c1
{
long double * coords;
...
}
I also have a second class cl2:
class cl2
{
vector<cl1*> cl1_vec;
unsigned int d;
...
}
I would like to sort cl1_vec, from cl2, based on coords[d], using the sort function for vectors.
So i could have something like
sort(cl2_inst->cl1_vec.begin(),cl2_inst->cl1_vec.end(), ??? );
I tried approches like
sort the 'std::vector' containing classes
C++ std::sort with predicate function in Class
but i couldn't make my way to solving this.
Thanks for any help that comes this way.
The code i've tried:
class cl1 {
public:
long double* coords;
cl1(long double *, unsigned int);
cl1();
cl1(const cl1& orig);
virtual ~cl1();
};
class cl2 {
public:
unsigned int d;
vector<cl1*> cl1_vec;
//the srting functions
static bool compareMyDataPredicate(cl1* lhs, cl1* rhs)
{
return (lhs->coords[d] < rhs->coords[d]);
};
// declare the functor nested within MyData.
struct compareMyDataFunctor : public binary_function<my_point*, my_point*, bool>
{
bool operator()( cl1* lhs, cl1* rhs)
{
return (lhs->coords[d] < rhs->coords[d]);
}
};
...
...
}
then in main
std::sort(cl2_inst->cl1_vec.begin(),cl2_inst->cl1_vec.end(),cl2::compareMyDataPredicate() );
The error is because you are accessing a non-static member d from a static context of the comparator function. Use the second approach, in the following way:
Provide a constructor to that struct, which takes a parameter unsigned int and sets a member to that value.
Create an object of type compareMyDataFunctor, and pass in the value of d to the constructor.
Use this object for sorting (3rd argument to std::sort)
I am not sure about the problems, because you were not precise enough about what exactly "does not work" means in your case (does not compile, does compile but does not sort etc). In case it does not compile (most likely guess) you did not post the error messages, which also makes finding and explaining the problem very hard.
Here are some guesses based on the code you posted:
Both static function as well as the functor use the member d to decide which column to sort on. However d is an instance variable, so it is not available for anything which is static. Neither the functor nor the static member function would know which of the possible ds to use, as there is one d per instance.
The best way to do this without resorting to C++11 features (lamdas) is to provide a constructor to the functor which takes the d you are planning to use. Something like this:
struct compareMyDataFunctor : public binary_function<cl1*, cl1*, bool>
{
compareMyDataFunctor( unsigned int d ) : d( d ) {}
bool operator()( cl1* lhs, cl1* rhs)
{
return (lhs->coords[d] < rhs->coords[d]);
}
unsigned int d;
};
This should do the trick.
There are some more things wrong with the code you posted though:
Arrays should be indexed using type size_t not a unsigned int. Same goes for std::vectors
The types in the std::binary_function instantiation do not match the actual types in the method (may be a problem of reducing the code).
Do not use using namespace std (I assume you do from the declarations in your code).
Functors such as these should take parameters as const-reference, not by value.
That's all I can think of. Next time try to present short, self contained, complete examples, then people will not have to resort to guessing.

How can I use std::generate/generate_n with a polymorphic function object?

I'm new to std::generate and have attempted to structure a program which uses it to initialize vectors. However it's behaving differently to my expectations.
I have an abstract base class:
template <typename G>
class RandomAllele {
public:
RandomAllele() { /* empty */ }
virtual ~RandomAllele() { /* empty */ }
virtual G operator()() const = 0;
};
Which is extended by (for example):
class RandomInt : public RandomAllele<int> {
public:
RandomInt(int max) : max_(max) {}
int operator()() const { return rand() % max_; }
private:
int max_;
};
I pass an instance of my inheriting class to a factory class by pointer, and then use it as the third argument for std::generate:
template<typename G, typename F>
class IndividualFactory {
public:
IndividualFactory(int length, const RandomAllele<G> *random_allele)
: length_(length), random_allele_(random_allele) { /* empty */ }
individual_type *generate_random() const {
std::vector<G> *chromosome = new std::vector<G>(length_);
std::generate(chromosome->begin(), chromosome->end(), *random_allele_); */
return new individual_type(chromosome);
}
private:
int length_;
RandomAllele<G> *random_allele_;
};
Now I get an error saying that RandomAllele cannot be instantiated because it's an abstract class. Why does generate need to instantiate it when the pointer already exists? And why is it trying to use the base class instead of the inheriting class RandomInt?
This works fine if I replace std::generate with:
for(auto iter = chromosome->begin(); iter != chromosome->end(); ++iter)
*iter = (*random_allele_)();
But I still wish to understand why it behaves strangely, and I'd prefer to use generate if there is a way to do this.
Thanks for your time,
Rhys
As others have mentioned above, the generate and generate_n functions take their generator objects by value, precluding you from directly using inheritance in this context.
However, one trick you can do is to apply the Fundamental Theorem of Software Engineering:
Any problem can be solved by adding another layer of indirection
Rather than directly passing in a polymorphic functor, instead pass in a wrapper functor that stores a pointer to this polymorphic functor and then forwards the call appropriately. For example:
template <typename T> class IndirectFunctor {
public:
explicit IndirectFunctor(RandomAllele<T>* f) : functor(f) {
// Handled in initializer list
}
T operator() () const {
return (*functor)();
}
private:
RandomAllele<T>* functor;
};
If you then pass this object into generate, as seen here:
RandomAllele<T>* functor = /* ... create an allele ... */
std::generate(begin, end, IndirectFunctor<T>(functor));
Then everything will work as intended. The reason for this is that if you copy IndirectFunctor<T> by value, then you just shallow-copy the stored pointer, which will still point to the RandomAllele you want to call. This avoids the slicing problem you were encountering because it never tries directly copying an object of type RandomAllele through a base class pointer. It always copies the wrapper object, which never tries to duplicate RandomAllele.
Hope this helps!
std::generate's generator is passed by value, and therefore copied.
In general the C++ standard library implements static polymorphism (templates) and doesn't support runtime polymorphism (virtual methods) for function objects. This is because it passes all its function objects by values, assuming them to be stateless or almost stateless such that the added indirection of passing by pointer or reference would be more expensive than by value.
Since it's passed by value this results in slicing and when you try to use a RandomAllele<G> it thinks you mean that exact class not whatever derived type it actually points to. Instead of templating on G just template on the exact generator functor type you desired directly.
The issue is that all standard algorithms take their arguments by value, to conform with traditional C constraints. So here the std::generate() algorithm take the functor by value. Your functor, of type RandomAllele<int>, is of abstract type. Yes, it's a pointer pointing at a concrete type, but the pointer is of an abstract type. In copying this object, the algorithm calls the copy constructor of RandomAllele<int>; i.e., the algorithm constructs an instance of abstract type. And this is something the C++ language forbids.
You can tell the runtime environment not to worry too much like so:
RandomInt *cp = dynamic_cast<RandomInt*>(random_allele);
if( ! cp ) {
// i thought the pointer is of RandomInt. It isn't. Err.
std::terminate(); // or something
}
std::generate(chromosome->begin(), chromosome->end(), *cp);
The prototype is:
template <class ForwardIterator, class Generator>
void generate ( ForwardIterator first, ForwardIterator last, Generator gen );
Hence gen is passed by value, so the compiler attempts to construct a RandomAllele by copy, hence problem.
The solution is to use an Envelope to provide the needed indirection:
template<class G>
class RandomAlleleEnvelope
{
public:
RandomAlleleEnvelope(const RandomAllele<G>* ra)
: ra_(ra)
{}
int operator()() const { return (*ra_)(); }
private:
const RandomAllele<G>* ra_;
};
std::generate<std::vector<int>::iterator,RandomAlleleEnvelope<int> >(chromosome->begin(), chromosome->end(), random_allele_);
Also note there is another solution, define your own generate to use a reference:
template <class ForwardIterator, class Generator>
void referenceGenerate ( ForwardIterator first, ForwardIterator last,
const Generator& gen )
{
while (first != last) *first++ = gen();
}
referenceGenerate(chromosome->begin(), chromosome->end(), *random_allele_);
I also think the following should work, that is to use the standard generate and explicitly make it handle a reference type:
std::generate<std::vector<int>::iterator, const RandomAllele<int>& >
(chromosome->begin(), chromosome->end(), *random_allele_);
I say should because this fails is instantiate on VS2010. On the other hand, if I can define my own:
template <class ForwardIterator, class Generator>
void myGenerate ( ForwardIterator first, ForwardIterator last, Generator gen )
{
while (first != last) *first++ = gen();
}
myGenerate<std::vector<int>::iterator, const RandomAllele<int>& >
(chromosome->begin(), chromosome->end(), *random_allele_);
The VS2010 fails because it implements std::generate is terms of another std::generate which defaults back to non-reference parameters.