I have implemented my own container:
template<typename T>
class MyContainer
{
// body where in some point 2 elements of collection are compared (-1, 0 and 1 possible comparison results)
};
What I want to do is add support of function objects, just like in std::set, where it is possible to do function object like this:
struct Comparator
{
bool operator()(const char* s1, const char* s2) const
{
return strcmp(s1, s2) < 0;
}
};
and then pass it as set parameter:
std::set<const char*, Comparator> SomeSet;
I'm not every-day C++ programmer, so I need help to achieve that. What must I do in order to add support to this? Must I create field in MyContainer in order to store function object in it to use it in my sorting methods inside container?
I resolved it by adding default template value, and defining default comparing class:
template<typename T, class Compare = DefaultTreeOrder<T>>
class MyContainer
{
private:
Compare compare;
public:
MyContainer()
{
compare = Compare();
}
};
where DefaultTreeOrder is:
template<typename T>
class DefaultTreeOrder
{
public:
int operator()(T value1, T value2)
{
less<T> l;
greater<T> g;
if(l(value1, value2))
{
return 1;
}
else if(g(value1, value2))
{
return -1;
}
return 0;
}
};
Related
I am implementing an object that makes use of unordered_map. The object is to be generic, so templates everywhere. In particular the operator== and operator() are wrapped into structures that are used by the unordered_map to respectively check if keys are equal and to generate hash values for keys. I'd like the user to write their own functions that implement the above two operators and pass those methods as input to the class object. The structs would then use those objects. I'm having some trouble with scopes and can't seem to figure out how to do it. Here's my code:
#include <unordered_map>
#include <iostream>
#include <string>
#include <functional>
template <typename O>
class aClass
{
public:
aClass( bool (usrIsEq)(O, O) ,
std::size_t (usrHashFtn)(O) )
{
this->usrIsEq = usrIsEq;
this->usrHashFtn = usrHashFtn;
}
void add(O k, std::string v)
{
iTable[ {k} ] = v;
}
std::string get(O k)
{
return iTable[ {k} ];
}
private:
bool (*usrIsEq)(O, O);
std::size_t (*usrHashFtn)(O);
struct Key
{
O obj;
bool operator==(const Key &other) const
{
std::cout << "obj " << obj << std::endl;
return usrIsEq(obj, other.obj);
}
};
struct KeyHasher
{
std::size_t operator()(const Key &k) const
{
return usrHashFtn(k);
}
};
std::unordered_map<Key, std::string, KeyHasher> iTable;
};
bool isEqInts(int a, int b)
{
return a == b;
}
std::size_t intHashFtn(int x)
{
std::hash<int> hf;
return hf(x);
}
int main()
{
aClass<int> x(isEqInts, intHashFtn);
x.add( 1, std::string("hello") );
}
I'm not entirely sure how to implement the structs Key and KeyHasher so that they use the functions contained inside the class. The only thing I truly care about is that the functions are given as input to the class constructor. Everything else can be scrapped.
The main problem that's tripping you up is that Key has no knowledge usrIsEq and KeyHasher has no knowledge of usrHashFtn. You need to pass a pointer or reference to an object of aClass to those classes.
Here' one suggestion:
struct Key
{
O obj;
aClass* ac;
bool operator==(const Key &other) const
{
std::cout << "obj " << obj << std::endl;
return ac->usrIsEq(obj, other.obj);
}
};
struct KeyHasher
{
std::size_t operator()(const Key &k) const
{
return k.ac->usrHashFtn(k.obj);
}
};
and update the places where you use Key to access the table:
void add(O k, std::string v)
{
iTable[{k, this}] = v;
}
std::string get(O k)
{
return iTable[{k, this}];
}
I am designing a custom ErrorInfo class which can be implemented by other modules to implement their specific error info class. The errors are maintained in a custom map where the key is a custom key defined by the module which is implementing the base class. The key is a template argument to the base class.
Here is the sample base class and a derived class.
#include <iostream>
#include <vector>
#include <string>
#include <map>
using namespace std;
template <class K>
class ErrorInfo {
public:
ErrorInfo(){};
void setTraceAll()
{
_traceAll = true;
}
bool isSetTraceAll()
{
return _traceAll;
}
bool insert(K key, int i)
{
errorMap.insert(std::pair<K,int>(key,i));
}
bool size()
{
return errorMap.size();
}
private:
std::map<K, int> errorMap;
bool _traceAll;
};
class MyCustomKey
{
private:
int _errorCode;
public:
MyCustomKey(int errorCode): _errorCode(errorCode).
{
}
bool operator<(const MyCustomKey &rhs) const
{
return _errorCode < rhs._errorCode;
}
};
class MyCustomErrroInfo: public ErrorInfo<MyCustomKey>
{
public:
MyCustomErrroInfo(){};
};
int main(){
MyCustomErrroInfo a;
a.insert(MyCustomKey(1), 1);
a.insert(MyCustomKey(2), 2);
cout<<"Size: "<<a.size()<<endl;
}
Although I am inserting two different keys in the main function, the size of the map is always 1. Other than overloading the < operator I am not sure what I am missing here. Any help on what I might be doing wrong would be appreciated.
bool size()
{
return errorMap.size();
}
If you want to get the size you shouldn't be using bool..
You defined member function size as having return type bool
bool size()
{
return errorMap.size();
}
So the return value can be converted to an integral value either 0 or 1.
Define the function for example like
size_t size()
{
return errorMap.size();
}
Also member function insert returns nothing
bool insert(K key, int i)
{
errorMap.insert(std::pair<K,int>(key,i));
}
It should look like
bool insert(K key, int i)
{
return errorMap.insert(std::pair<K,int>(key,i)).second;
}
I'm trying to hold a polymorphic type as a key in a map.
I came up with the following two structures:
Note that Game is an abstract class and the data structure I use is :
std::unordered_map<gamePtr,int> _allGames;
while gamePtr is a typedef for:
unique_ptr<Game>
template<>
struct std::hash<std::unique_ptr<Game>> {
size_t operator()(std::unique_ptr<Game> game) const {
return (std::hash<string>()(std::to_string(game->firstTeamFinalScore()) + game->firstTeam() + game->secondTeam()));
}
};
struct cmp_games {
bool operator() (std::unique_ptr<Game> game1, std::unique_ptr<Game> game2) const {
return *game1 == *game2;
}
};
The cmp_games comparator seems to work fine but the std::hash does not because it tries to copy a unique_ptr (Which is ofc impossible) and I've no idea how to get over it.
Would love to hear some suggestions (If that is even possible).
EDIT: The comparator also doesn't seem to work properly. how do I make this map work correctly with unique_ptr as a key?
EDIT2:
Came up with:
template<>
struct std::hash<std::unique_ptr<Game>> {
size_t operator()(const std::unique_ptr<Game>& game) const {
return (std::hash<string>()(std::to_string(game->firstTeamFinalScore()) + game->firstTeam() + game->secondTeam()));
}
};
template<>
struct std::equal_to<std::unique_ptr<Game>> {
bool operator() (const std::unique_ptr<Game>& game1,const std::unique_ptr<Game>& game2) const {
return *game1 == *game2;
}
};
Should they be enough?
The standard provides a specilization so that std::hash<unique_ptr<T>> is the same as std::hash<T*>. So provide a specialization for std::hash<Game *>. For example:
#include <iostream>
#include <memory>
#include <unordered_map>
#include <cstdlib>
struct foo
{
foo(unsigned i) : i(i) {}
unsigned i;
};
namespace std {
template<>
struct hash<foo *>
{
size_t operator()(foo const *f) const
{
std::cout << "Hashing foo: " << f->i << '\n';
return f->i;;
}
};
}
int main()
{
std::unordered_map<std::unique_ptr<foo>, int> m;
m.insert(std::make_pair(std::unique_ptr<foo>(new foo(10)), 100));
m.insert(std::make_pair(std::unique_ptr<foo>(new foo(20)), 200));
}
Live demo
Another option is to change your existing std::hash specialization so that it takes the unique_ptr by reference.
size_t operator()(std::unique_ptr<Game> const& game) const
// ^^^^^^ no more copying
EDIT: std::unique_ptr provides comparison operators that compare the managed pointers. If you want the unordered_map to test the Game objects themselves for equality, provide an operator== overload instead of specializing std::equal_to
inline bool operator==(const std::unique_ptr<Game>& game1,
const std::unique_ptr<Game>& game2)
{
return *game1 == *game2;
}
This, in turn, requires that you've provided an equality operator for Game (or you could just add the logic to the function above).
inline bool operator==(Game const& game1, Game const& game2)
{
return // however you want to compare these
}
Pass the game by const reference into std::hash::operator():
template<>
struct std::hash<std::unique_ptr<Game>> {
size_t operator()(const std::unique_ptr<Game>& game) const;
}
The same applies to cmp_games::operator().
Sorry for the unclear title, actually I couldn't think of a title that describes my problem concisely.
But the question is simple to state. I have a Node class. I want to maintain order among its objects by its id_ field. I know that making a multiset<Node> will correctly maintain the order in the container if I overload < operator in Node class or provide a Comparator object in multiset. But I want to declare a multiset<Node*> container and want to achieve the same behaviour.
Here is my Node class definition:
class Node {
int id_;
...
public:
Node() {
...
}
int getId() {
return id_;
}
void setId(int id) {
id_ = id;
}
...
bool operator<(const Node &input) {
return (this->id_ < input.id_);
}
};
What do I do?
I think what you mean and what you need is this:
template <typename T, typename Pred = std::less<T>>
struct ptr_compare : Pred
{
ptr_compare(Pred const & p = Pred()) : Pred(p) { }
bool operator()(T const * p1, T const * p2) const
{
return Pred::operator()(*p1, *p2);
}
};
typedef std::multiset<Node*, ptr_compare<Node>> node_ptr_set;
You can use the ptr_compare template for any container that requires a binary predicate and you want to apply the predicate indirectly.
It is possible to distinguish when template parameter in functor represents an object or a pointer to object?
class Comparator
{
public:
template <typename Object>
bool operator() ( const Object &o1, const Object &o2 ) const
{
return ( o1.getID() < o2.getID() );
}
template <typename Object>
bool operator() ( const Object *o1, const Object *o2 ) const
{
return ( o1->getID() < o2->getID() );
}
};
Objects or pointers are stored in generic container List, that should be sorted using the Comparator class
int main()
{
List <Object *> objects1;
std::sort(objects1.begin(), objects1.end(), Comparator());
List <Object> objects2;
std::sort(objects2.begin(), objects2.end(), Comparator());
);
Currently I am using two comparators (Comparator1, Comparator2) but I do not find it comfortable...
You could templatetify the Comparator itself:
template<typename Object>
class Comparator {
public:
bool operator()(const Object &o1, const Object &o2) const {
return (o1.getID() < o2.getID());
}
bool operator()(const Object *o1, const Object *o2) const {
return (o1->getID() < o2->getID());
}
};
int main() {
std::vector objects1;
std::sort(objects1.begin(), objects1.end(), Comparator<Object> ());
std::vector objects2;
std::sort(objects2.begin(), objects2.end(), Comparator<Object> ());
return 0;
}
This way it doesn't even generate two separate comparators!
Given your architecture (one list of Objects, another of Object*s) you really have no alternative.
Do you really need two lists?