How do I initialize a std::set comparator? - c++

I need to initialize some comparator of the new data type TType based on std::set with some object o of another class Object:
typedef std::set <unsigned int, sortSet(o)> TType
This declaration is otside the class (in header file). At the time of the declaration this object does not have to exist, it will be created later.
class sortSet
{
private:
Object o;
public:
sortSet(Object &oo): o(oo) {}
bool operator() ( const unsigned int &i1, const unsigned int &i2 ) const
{
//Some code...
}
};
If the declaration was inside some method (when object has already been created), situation would be quite simple... What can I do?

The template parameter needs to be the type of the comparator, not a specific object of that type; you can provide a specific comparator object to be used in the std::set constructor:
typedef std::set<unsigned int, sortSet> TType;
Object o;
TType mySet(sortSet(o));

I am not sure if I understood your actual question, however, the general idiom to use a custom comparator is shown in the following contrived example.
#include <set>
class foo {
public:
int i_;
};
struct foo_comparator {
bool operator()( foo const & lhs, foo const & rhs ) {
return lhs.i_ < rhs.i_;
}
};
typedef std::set< foo, foo_comparator > foo_set;
int main() {
foo_set my_foo_set;
}

Related

C++ How can I use an unordered_map with custom hash & compare as member variable if those functions get passed in Constructor?

Assume I have this class
class C {
private:
std::unordered_map<struct MyStruct, int> map;
public:
C(size_t(*hash)(const struct MyStruct &t1), bool(*comp)(const struct MyStruct &t1, const struct MyStruct &t2);
}
How can I use the function pointers in my unordered_map but still have the map as a member variable? Because at the time when I get these function pointers in the Constructor, the map is already created.
Considering the fact that you have tagged your Q with C++14, I will post my answer with std::functions instead of function pointers. You can write your class C like this:
using hash_t = std::function<size_t(const struct MyStruct &t1)>;
using comp_t = std::function<bool(const struct MyStruct &t1, const struct MyStruct &t2)>;
class C
{
private:
std::unordered_map<struct MyStruct, int, hash_t, comp_t> map;
public:
C(int bucket_size, hash_t hasher, comp_t comper) :
map(bucket_size, hasher, comper)
{
}
};
and then instantiate your class with the required parameters. See the live demo here.

Virtually turn vector of struct into vector of struct members

I have a function that takes a vector-like input. To simplify things, let's use this print_in_order function:
#include <iostream>
#include <vector>
template <typename vectorlike>
void print_in_order(std::vector<int> const & order,
vectorlike const & printme) {
for (int i : order)
std::cout << printme[i] << std::endl;
}
int main() {
std::vector<int> printme = {100, 200, 300};
std::vector<int> order = {2,0,1};
print_in_order(order, printme);
}
Now I have a vector<Elem> and want to print a single integer member, Elem.a, for each Elem in the vector. I could do this by creating a new vector<int> (copying a for all Elems) and pass this to the print function - however, I feel like there must be a way to pass a "virtual" vector that, when operator[] is used on it, returns this only the member a. Note that I don't want to change the print_in_order function to access the member, it should remain general.
Is this possible, maybe with a lambda expression?
Full code below.
#include <iostream>
#include <vector>
struct Elem {
int a,b;
Elem(int a, int b) : a(a),b(b) {}
};
template <typename vectorlike>
void print_in_order(std::vector<int> const & order,
vectorlike const & printme) {
for (int i : order)
std::cout << printme[i] << std::endl;
}
int main() {
std::vector<Elem> printme = {Elem(1,100), Elem(2,200), Elem(3,300)};
std::vector<int> order = {2,0,1};
// how to do this?
virtual_vector X(printme) // behaves like a std::vector<Elem.a>
print_in_order(order, X);
}
It's not really possible to directly do what you want. Instead you might want to take a hint from the standard algorithm library, for example std::for_each where you take an extra argument that is a function-like object that you call for each element. Then you could easily pass a lambda function that prints only the wanted element.
Perhaps something like
template<typename vectorlike, typename functionlike>
void print_in_order(std::vector<int> const & order,
vectorlike const & printme,
functionlike func) {
for (int i : order)
func(printme[i]);
}
Then call it like
print_in_order(order, printme, [](Elem const& elem) {
std::cout << elem.a;
});
Since C++ have function overloading you can still keep the old print_in_order function for plain vectors.
Using member pointers you can implement a proxy type that will allow you view a container of objects by substituting each object by one of it's members (see pointer to data member) or by one of it's getters (see pointer to member function). The first solution addresses only data members, the second accounts for both.
The container will necessarily need to know which container to use and which member to map, which will be provided at construction. The type of a pointer to member depends on the type of that member so it will have to be considered as an additional template argument.
template<class Container, class MemberPtr>
class virtual_vector
{
public:
virtual_vector(const Container & p_container, MemberPtr p_member_ptr) :
m_container(&p_container),
m_member(p_member_ptr)
{}
private:
const Container * m_container;
MemberPtr m_member;
};
Next, implement the operator[] operator, since you mentioned that it's how you wanted to access your elements. The syntax for dereferencing a member pointer can be surprising at first.
template<class Container, class MemberPtr>
class virtual_vector
{
public:
virtual_vector(const Container & p_container, MemberPtr p_member_ptr) :
m_container(&p_container),
m_member(p_member_ptr)
{}
// Dispatch to the right get method
auto operator[](const size_t p_index) const
{
return (*m_container)[p_index].*m_member;
}
private:
const Container * m_container;
MemberPtr m_member;
};
To use this implementation, you would write something like this :
int main() {
std::vector<Elem> printme = { Elem(1,100), Elem(2,200), Elem(3,300) };
std::vector<int> order = { 2,0,1 };
virtual_vector<decltype(printme), decltype(&Elem::a)> X(printme, &Elem::a);
print_in_order(order, X);
}
This is a bit cumbersome since there is no template argument deduction happening. So lets add a free function to deduce the template arguments.
template<class Container, class MemberPtr>
virtual_vector<Container, MemberPtr>
make_virtual_vector(const Container & p_container, MemberPtr p_member_ptr)
{
return{ p_container, p_member_ptr };
}
The usage becomes :
int main() {
std::vector<Elem> printme = { Elem(1,100), Elem(2,200), Elem(3,300) };
std::vector<int> order = { 2,0,1 };
auto X = make_virtual_vector(printme, &Elem::a);
print_in_order(order, X);
}
If you want to support member functions, it's a little bit more complicated. First, the syntax to dereference a data member pointer is slightly different from calling a function member pointer. You have to implement two versions of the operator[] and enable the correct one based on the member pointer type. Luckily the standard provides std::enable_if and std::is_member_function_pointer (both in the <type_trait> header) which allow us to do just that. The member function pointer requires you to specify the arguments to pass to the function (non in this case) and an extra set of parentheses around the expression that would evaluate to the function to call (everything before the list of arguments).
template<class Container, class MemberPtr>
class virtual_vector
{
public:
virtual_vector(const Container & p_container, MemberPtr p_member_ptr) :
m_container(&p_container),
m_member(p_member_ptr)
{}
// For mapping to a method
template<class T = MemberPtr>
auto operator[](std::enable_if_t<std::is_member_function_pointer<T>::value == true, const size_t> p_index) const
{
return ((*m_container)[p_index].*m_member)();
}
// For mapping to a member
template<class T = MemberPtr>
auto operator[](std::enable_if_t<std::is_member_function_pointer<T>::value == false, const size_t> p_index) const
{
return (*m_container)[p_index].*m_member;
}
private:
const Container * m_container;
MemberPtr m_member;
};
To test this, I've added a getter to the Elem class, for illustrative purposes.
struct Elem {
int a, b;
int foo() const { return a; }
Elem(int a, int b) : a(a), b(b) {}
};
And here is how it would be used :
int main() {
std::vector<Elem> printme = { Elem(1,100), Elem(2,200), Elem(3,300) };
std::vector<int> order = { 2,0,1 };
{ // print member
auto X = make_virtual_vector(printme, &Elem::a);
print_in_order(order, X);
}
{ // print method
auto X = make_virtual_vector(printme, &Elem::foo);
print_in_order(order, X);
}
}
You've got a choice of two data structures
struct Employee
{
std::string name;
double salary;
long payrollid;
};
std::vector<Employee> employees;
Or alternatively
struct Employees
{
std::vector<std::string> names;
std::vector<double> salaries;
std::vector<long> payrollids;
};
C++ is designed with the first option as the default. Other languages such as Javascript tend to encourage the second option.
If you want to find mean salary, option 2 is more convenient. If you want to sort the employees by salary, option 1 is easier to work with.
However you can use lamdas to partially interconvert between the two. The lambda is a trivial little function which takes an Employee and returns a salary for him - so effectively providing a flat vector of doubles we can take the mean of - or takes an index and an Employees and returns an employee, doing a little bit of trivial data reformatting.
template<class F>
struct index_fake_t{
F f;
decltype(auto) operator[](std::size_t i)const{
return f(i);
}
};
template<class F>
index_fake_t<F> index_fake( F f ){
return{std::move(f)};
}
template<class F>
auto reindexer(F f){
return [f=std::move(f)](auto&& v)mutable{
return index_fake([f=std::move(f),&v](auto i)->decltype(auto){
return v[f(i)];
});
};
}
template<class F>
auto indexer_mapper(F f){
return [f=std::move(f)](auto&& v)mutable{
return index_fake([f=std::move(f),&v](auto i)->decltype(auto){
return f(v[i]);
});
};
}
Now, print in order can be rewritten as:
template <typename vectorlike>
void print(vectorlike const & printme) {
for (auto&& x:printme)
std::cout << x << std::endl;
}
template <typename vectorlike>
void print_in_order(std::vector<int> const& reorder, vectorlike const & printme) {
print(reindexer([&](auto i){return reorder[i];})(printme));
}
and printing .a as:
print_in_order( reorder, indexer_mapper([](auto&&x){return x.a;})(printme) );
there may be some typos.

c++ method as template argument

I am trying to specialize std::unordered_map for a class X with a custom hash and a custom equality. The problem is that both the equality and hash functions do not depend only on the object(s) of class X but also on data in another (fixed) object of another class Y. Here is a toy example (with only the hash function) of what I want to do:
#include <unordered_map>
using namespace std;
struct Y {
bool b;
struct X {
size_t i;
};
size_t hash(const X &x) {
return x.i + b;
}
unordered_map<X, int, hash> mymap;
};
The problem is that the function hash in the template specialization is a method and the compiler complains ("call to non-static member function without an object argument"). What I want is that y.mymap uses y.hash(). Any way to do this?
Note that in the real code Y is also a template, in case it matters.
Thanks!
EDIT: To clarify, instead of the boolean b in my code I have a vector with data that is needed in comparing objects of type X. Some data is added when an X is created, so the vector is not constant, but the data for a given X does not change after it is added, so the hash for a given X never changes (so in a sense it depends only on X as required for a hash). The main reason I use this approach is to save memory since this data is a lot and is usually shared.
You can use function<size_t(X const&)> and e.g. bind, but as type erasure is not necessary in this case, here is a simpler solution:
struct Y {
bool b;
struct X {
size_t i;
bool operator==(X x) const {return i == x.i;}
};
size_t hash(const X &x) {
return x.i + b;
}
struct Hasher {
Y* this_;
template <typename T>
auto operator()(T&& t) const
-> decltype(this_->hash(std::forward<T>(t))) {
return this_->hash(std::forward<T>(t));
}
};
unordered_map<X, int, Hasher> mymap;
Y() : b(false),
mymap(0, {this}) {}
};
As mentioned by #dyp in the comments, you have to be careful with special member functions since we implicitly store this in mymap - i.e. the compiler-generated definitions would copy the this_ pointer. An example implementation of the move constructor could be
Y(Y&& y) : b(y.b), mymap(std::make_move_iterator(std::begin(y.mymap)),
std::make_move_iterator(std::end (y.mymap)), 0, {this}) {}
Unfortunately what you want to do is not legal. See 17.6.3.5/Table 26:
h(k) The value returned shall depend only on the argument k.
It's pretty clear that you aren't allowed to have the hash depend on a member of Y as well as X.
EDIT: Just in case you meant for b to be const in your Y class there is a solution (I didn't compile this yet, I will if I get a chance):
struct Y
{
explicit Y(bool config) : b(config), hash_(config), mymap(0, hash_) { }
const bool b;
struct X
{
size_t i;
};
struct Hash
{
explicit Hash(bool b) : b_(b) { }
size_t operator()(const X& x) const
{
return x.i + b_;
}
private:
bool b_;
};
Hash hash_;
unordered_map<X, int, Hash> mymap;
};

std::vector inserting std::pair

I am having trouble trying to insert a std::pair in the std::vector, with this code:
template <class R>
class AVectorContainner
{
public:
AVectorContainner()
{
mVector= new std::vector<entry>;
}
typedef std::pair<int ,R *> entry;
void insert(R* aPointer, int aID)
{
entry aEntry;
aEntry=std::make_pair(aID,aPointer );
mVector->push_back(aEntry);
}
private:
std::vector<entry> * mVector;
}
This is the part of the main file, that I declare a pointer of a class and then I used it in the initialization of the template class.
In the main.cpp:
int main()
{
SomeType * aTipe= new SomeType;
int aID=1;
AVectorContainer<SomeType> * aContainer= new AVectorContainer;
aContainer->insert(aTipe,aId);//error line
delete aTipe;
delete aContainer;
return 0;
}
Compiler Output:
error: non-static reference member 'const int& std::pair<const int&, SomeType *>::first', can't use default assignment operator
error: value-initialization of reference type 'const int&'
The original poster failed to actually post the code that was causing the problem.
He has since edited my post with the correct code that demonstrates the problem. The code that demonstrates the problem follows:
template <class R, typename B=int>
class AVectorContainer
{
public:
AVectorContainer() {}
typedef R* ptr_Type;
typedef const B & const_ref_Type;
typedef std::pair<const_ref_Type ,ptr_Type> entry;
void insert(ptr_Type aPointer, const_ref_Type aID) {
entry aEntry=std::make_pair(aID,aPointer);
mVector.push_back(aEntry);
}
private:
std::vector<entry> mVector;
};
class SomeType
{
public:
SomeType(){ x=5; }
~SomeType(){ }
int x;
};
int main()
{
SomeType * aTipe= new SomeType;
int aID=1;
AVectorContainer<SomeType> aContainer;
aContainer.insert(aTipe,aID);
return 0;
}
Compiler output:
/usr/include/c++/4.7/bits/stl_pair.h:88: error: non-static reference member 'const int& std::pair<const int&, SomeType*>::first', can't use default assignment operator
The flaw is in these lines:
typedef R* ptr_Type;
typedef const B & const_ref_Type;
typedef std::pair<const_ref_Type ,ptr_Type> entry;
std::vector<entry> mVector;
Here, the original poster attempts to make a vector of pairs that contain a constant reference, and then does this:
entry aEntry;
aEntry=std::make_pair(aID,aPointer )
this attempts to assign one pair to another. But const& variables cannot be assigned to another -- they can be constructed (initialized) from another const&, but not assigned.
An easy fix is:
entry aEntry=std::make_pair(aID,aPointer )
so that we are not constructing aEntry from another entry, instead of default constructing aEntry (which is also illegal: const& must be initialized), then assigning to it.
Fixed all typos, compare the two ... he did like 100 in 20 lines!
#include <vector>
#include <utility>
template <class R>
class AVectorContainer
{
public:
AVectorContainer()
{
mVector= new std::vector<entry>;
}
typedef std::pair<int ,R *> entry;
void insert(R* aPointer, int aID)
{
entry aEntry;
aEntry=std::make_pair(aID,aPointer );
mVector->push_back(aEntry);
}
private:
std::vector<entry> * mVector;
};
class SomeType
{
public:
SomeType(){ x=5; }
~SomeType(){ }
int x;
};
int main()
{
SomeType * aTipe= new SomeType;
int aID=1;
AVectorContainer<SomeType> * aContainer= new AVectorContainer<SomeType>;
aContainer->insert(aTipe,aID);//error line
return 0;
}
After fixing all the typo's (Containner, aId, missing ; etc.) the code compiles just fine.

How to implement sorting method for a c++ priority_queue with pointers

My priority queue declared as:
std::priority_queue<*MyClass> queue;
class MyClass {
bool operator<( const MyClass* m ) const;
}
is not sorting the items in the queue.
What is wrong? I would not like to implement a different (Compare) class.
Answer summary:
The problem is, the pointer addresses are sorted. The only way to avoid this is a class that 'compares the pointers'.
Now implemented as:
std::priority_queue<*MyClass, vector<*MyClass>, MyClass::CompStr > queue;
class MyClass {
struct CompStr {
bool operator()(MyClass* m1, MyClass* m2);
}
}
Give the que the Compare functor ptr_less.
If you want the ptr_less to be compatible with the rest of the std library (binders, composers, ... ):
template<class T>
struct ptr_less
: public binary_function<T, T, bool> {
bool operator()(const T& left, const T& right) const{
return ((*left) <( *right));
}
};
std::priority_queue<MyClass*, vector<MyClass*>, ptr_less<MyClass*> > que;
Otherwise you can get away with the simplified version:
struct ptr_less {
template<class T>
bool operator()(const T& left, const T& right) const {
return ((*left) <( *right));
}
};
std::priority_queue<MyClass*, vector<MyClass*>, ptr_less > que;
The operator <() you have provided will compare a MyClass object with a pointer to a MyClass object. But your queue contains only pointers (I think). You need a comparison function that takes two pointers as parameters.
All this is based on some suppositions - please post your actual code, using copy and paste.
Since your priority_queue contains only pointer values, it will use the default comparison operator for the pointers - this will sort them by address which is obviously not what you want. If you change the priority_queue to store the class instances by value, it will use the operator you defined. Or, you will have to provide a comparison function.
Not sure about the priority queue stuff because I've never used it but to do a straight sort, you can do this:
class A
{
friend struct ComparePtrToA;
public:
A( int v=0 ):a(v){}
private:
int a;
};
struct ComparePtrToA
{
bool operator()(A* a1, A* a2) {return a1->a < a2->a;}
};
#include <vector>
#include <algorithm>
int _tmain(int argc, _TCHAR* argv[])
{
vector<A*> someAs;
someAs.push_back(new A(1));
someAs.push_back(new A(3));
someAs.push_back(new A(2));
sort( someAs.begin(), someAs.end(), ComparePtrToA() );
}
Note the memory leaks, this is only an example...
Further note: This is not intended to be an implementation of priority queue! The vector is simply an example of using the functor I created to compare two objects via their pointers. Although I'm aware of what a priority queue is and roughly how it works, I have never used the STL features that implement them.
Update: I think TimW makes some valid points. I don't know why he was downvoted so much. I think my answer can be improved as follows:
class A
{
public:
A( int v=0 ):a(v){}
bool operator<( const A& rhs ) { return a < rhs.a; }
private:
int a;
};
struct ComparePtrToA
{
bool operator()(A* a1, A* a2) {return *a1 < *a2;}
};
which is cleaner (especially if you consider having a container of values rather than pointers - no further work would be necessary).