Custom comparator for multiset that contains pointers to objects - c++

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.

Related

adding functionality onto polymorphic tree in c++

I have a polymorphic tree and I'm trying to do add functionality like comparing two nodes without using RTTI like dynamic_cast The approach I'm taking is the visitor pattern.
The issue I'm having is that the visitor pattern isn't letting me operate on any parameters or getting return types out of the functions.
For example if I wanted to write a visitor that compares two nodes
class AbstractDispatch{
public:
virtual void visit(NodeFoo &operand) = 0;
virtual void visit(NodeBar &operand) = 0;
//...for all types.
};
class CompareVisitor{
public:
void visit(NodeFoo &operand) override;
//...
};
class SetVisitor{
public:
void visit(NodeFoo &operand) override;
//...
};
void CompareVisitor::visit(NodeFoo &operand){
//compare operand to what?
//get result of comparison how?
}
void SetVisitor::visit(NodeFoo &operand){
//set operand to what?
}
My current idea is to add other functions and members to the visitor classes. This would let me do something like this:
Base *object = new NodeFoo();
CompareVisitor compare;
compare.set_parameters(NodeFoo(/* */));
object->accept(compare);
bool result = compare.get_result();
I could set the parameters of the compare visitor and traverse the tree with it checking for the nodes and doing other such operations in this fashion.
Another solution would be to store node-type information in the node and do a get_type() check for safe-casting.
dynamic_cast is slow but if the node-type hierarchy is extremely simple could it be faster? Are there better design patterns for doing something like this?
You could write a visitor that compares the current node with the previous one.
class Node{...}
class NodeFoo : public Node {...}
class NodeBar : public Node {...}
class visitor{
public:
void visit( const NodeFoo& node ){
//First node: store relevant comparison information to private variables
if( foo == nullptr ){
foo = &node;
}
//Other nodes: Compare to the stored data and store comparison result
else {
...
}
}
void visit( const NodeBar& node ){
...
}
bool result() const{ return result; };
private:
bool result = false;
//variables for comparison, could be this simple but also a variant type
// or plain Node*
NodeFoo* foo = nullptr;
NodeBar* bar = nullptr;
}
You would use it like
Node node1;
Node node2;
Visitor v;
node1.accept( v );
node2.accept( v );
v.result();
Sure, this is a very basic implementation, you could use a plain Node* to store the first node, if you presume that alle visited nodes have the same type. You could also use a variant type or store the type as string... ( you know the type by the executed visit function )
If the Node lifetime is not sure, you can store some Node depending data, that you need for the comparisson instead of a pointer to the node.... there are hundreds of possibilities, this is just a small sketch of the basic framework
It can be done with double visit ( = two virtual calls) if you allow CompareVisitor to have a state. I don't think there's a way around that given your visitor API.
#include <iostream>
#include <string>
#include <vector>
#include <memory>
struct FooNode;
struct BarNode;
struct Visitor
{
virtual void visit(FooNode&)=0;
virtual void visit(BarNode&)=0;
};
struct Node{
virtual void accept(Visitor& v) = 0;
};
struct FooNode: public Node{
virtual void accept(Visitor& v) override { v.visit(*this);}
const char* print(){return "FooNode";}
};
struct BarNode: public Node{
virtual void accept(Visitor& v) override { v.visit(*this);}
const char* print(){return "BarNode";}
};
using ret_type=std::string;
//Feel free to specialize or overload
//Or create comparator class that allows partial specializations
template<typename Left, typename Right>
ret_type compare(Left &left, Right& right){
return std::string(left.print()) + "<=>" + right.print() + '\n';
}
//Compares (visited) and (rightNode)
class RightCompareVisitor : public Visitor {
public:
RightCompareVisitor(Node& right):rightNode(right){}
void visit(FooNode &left) override
{
visitRightNode(left);
}
void visit(BarNode &left) override
{
visitRightNode(left);
}
ret_type getRes() { return std::move(result);}
private:
template<typename Left>
void visitRightNode(Left& left){
struct CompareVisitor: Visitor
{
ret_type& result;
Left& left;
CompareVisitor(ret_type& result, Left& left):result(result), left(left){}
void visit(FooNode &right) override final{
result = compare(left, right);
}
void visit(BarNode &right) override final{
result = compare(left, right);
}
};
CompareVisitor v(result, left);
rightNode.accept(v);
}
ret_type result;
Node& rightNode;
};
//If you add this then you can always just use 'compare' to compare any two
//nodes.
template<>
ret_type compare<Node,Node>(Node& left, Node& right){
RightCompareVisitor rC{right};
left.accept(rC);
return rC.getRes();
}
int main()
{
std::vector<std::unique_ptr<Node>> nodes;
nodes.emplace_back(std::make_unique<FooNode>());
nodes.emplace_back(std::make_unique<BarNode>());
nodes.emplace_back(std::make_unique<FooNode>());
for(auto&& left : nodes)
for(auto&& right: nodes)
std::cout<<compare(*left,*right);
}
Add consts where you want. If you want RightCompareVisitor to be reused then use pointers for nodes.
Output:
FooNode<=>FooNode
FooNode<=>BarNode
FooNode<=>FooNode
BarNode<=>FooNode
BarNode<=>BarNode
BarNode<=>FooNode
FooNode<=>FooNode
FooNode<=>BarNode
FooNode<=>FooNode

C++ discourages base class of collection - is there anyway to fake it?

There are no similar concept of (Java) Collection in C++.
I can understand the reason, but I want to know whether there is any way to fake it elegantly.
Example
I have implemented many custom Collections.
They all have Iterator that works correctly, similar to std::vector, std::unordered_set, etc.
They are MyArray<T> , MyBinaryTree<T> and MySet<T>.
Here I will show a working code that show the location I want to fake it.
Let's say that I have 2 levels of program : library and user.
It does only one thing - User commands Library to eat all Orange*s in a bucket.
Library.h
class Library{
public: static void eatAll(const MyArray<Orange*>& bucket);
};
Library.cpp
#include "Orange.h"
void Library::eatAll(const MyArray<Orange*>& bucket){
for(auto orange:bucket){
orange->eaten();
}
}
User.h
MyArray<Orange*> bucket;
Library::eatAll(bucket);
It is OK.
Now, I want Library::eatAll to also support MyBinaryTree<Orange*>, I have some not-so-desirable approaches as below.
My poor solution
1. Java way
Make MyBinaryTree<T> and MyArray<Orange*> (and their iterator) inherit from a new class Collection<T> (and CollectionIterator<T>).
change signature to Library::eatAll(const Collection<T>&)
Disadvantage : performance penalty from "virtual" of some functions in Collection<T>.
2. Template v1
//Library.h
template<class T> void eatAll(const T&t ){
for(auto orange : t){
orange->eaten();
}
}
make eatAll a template function
Disadvantage : The implementation of the eatAll must be in header.
I have to #include orange.h in Library.h.
Sometimes, I really want to just forward declaration.
3. Template v2
//Library.h
template<class T> void eatAll(const T&t ){
for(auto orange : t){
eatAnOrange(orange)
}
}
private: void eatAnOrange(Orange* orange){
//below implementation is inside Library.cpp
orange->eaten();
}
create a middle-man function eatAnOrange
Disadvantage :
Code is less readable, not concise, cause a little maintainability problem.
If there are a lot of other functions e.g. squeezeAll(), I probably have to create a lot of middle-man functions, e.g. squeezeAnOrange().
4. Operator=()
Create converter among the 3 collection classes via implicit constructor.
Disadvantage : Suffer performance from creating a new instance of collection.
//Here is what it will do, internally (roughly speaking)
MyBinaryTree<Orange*> bucket;
Library::eatAll(MyArray<Orange*>(bucket));
I believe my solutions are inelegant.
Are there any solutions that don't suffer the mentioned disadvantage?
Edit:
Both of current answers are elegant than my approaches (thank!), but still has disadvantage :-
- Oliv's requires #include "orange.h" in User.h.
- Richard Hodges's has virtual function calling.
In C++, collections are traversed using the iterator design pattern. The entire STL is designed around this concept. It may fit your needs:
You could define eatAll as a function that accept two iterators:
template<class Iterator,class Sentinel>
void eatAll(Iterator it, Sentinel s){
for (;it!=s;++it)
it->eaten();
}
Or the range like algorithm interface:
template<class Range>
void eatAll(Range& r){
for (auto& v:r)
v.eaten();
}
You will have to define you binary tree as a range (it must implement begin() and end()). Hopefully trees are kind of graph that can be linearised. All the smart work will then go in the iterator implementation!
If you want it truly polymorphic, then we have to deal with 2 things:
the actual type of the container
The fact that the result of dereferencing a map is a pair containing key and value references.
My view is that the answer to this is not to derive from containers, which is limiting, but to create a polymorphic "value iterator", which models all iterators and extracts their values correctly.
Then we can write code like this:
int main()
{
std::vector<Orange> vo {
Orange(), Orange()
};
std::map<int, Orange> mio {
{ 1, Orange() },
{ 2, Orange() },
{ 3, Orange() }
};
std::cout << "vector:\n";
auto first = makePolymorphicValueIterator(vo.begin());
auto last = makePolymorphicValueIterator(vo.end());
do_orange_things(first, last);
std::cout << "\nmap:\n";
first = makePolymorphicValueIterator(mio.begin());
last = makePolymorphicValueIterator(mio.end());
do_orange_things(first, last);
}
To get this:
vector:
Orange
Orange
map:
Orange
Orange
Orange
Here's a minimal, complete implementation:
#include <typeinfo>
#include <memory>
#include <iostream>
#include <vector>
#include <map>
#include <iterator>
// define an orange
struct Orange {
};
// a meta-function to get the type of the value of some iterated value_type
template<class ValueType> struct type_of_value
{
using type = ValueType;
};
// specialise it for maps and unordered maps
template<class K, class V> struct type_of_value<std::pair<K, V>>
{
using type = V;
};
template<class ValueType> using type_of_value_t = typename type_of_value<ValueType>::type;
// function to extract a value from an instance of a value_type
template<class ValueType> struct value_extractor
{
template<class V>
auto& operator()(V&& v) const {
return v;
}
};
// specialised for maps
template<class K, class V> struct value_extractor<std::pair<K, V>>
{
template<class Arg>
auto& operator()(Arg&& v) const {
return std::get<1>(v);
}
};
template<class Iter>
auto extract_value(Iter const& iter) -> auto&
{
using value_type = typename std::iterator_traits<Iter>::value_type;
auto e = value_extractor<value_type> {};
return e(*iter);
}
// a polymorphic (forward only at the moment) iterator
// which delivers the value (in the case of maps) or the element (every other container)
template<class ValueType>
struct PolymorphicValueIterator {
using value_type = type_of_value_t<ValueType>;
private:
struct iterator_details {
std::type_info const &type;
void *address;
};
struct concept {
virtual std::unique_ptr<concept> clone() const = 0;
virtual value_type& invoke_deref() const = 0;
virtual void invoke_next(std::size_t distance = 1) = 0;
virtual iterator_details get_details() = 0;
virtual bool is_equal(const iterator_details &other) const = 0;
virtual ~concept() = default;
};
template<class Iter>
struct model final : concept {
model(Iter iter)
: iter_(iter)
{}
std::unique_ptr<concept> clone() const override
{
return std::make_unique<model>(iter_);
}
virtual value_type& invoke_deref() const override {
return extract_value(iter_);
}
void invoke_next(std::size_t distance = 1) override
{
iter_ = std::next(iter_, distance);
}
iterator_details get_details() override {
return {
typeid(Iter),
std::addressof(iter_)
};
}
bool is_equal(const iterator_details &other) const override {
if (typeid(Iter) != other.type) {
return false;
}
auto pother = reinterpret_cast<Iter const*>(other.address);
Iter const& iother = *pother;
return iter_ == iother;
}
Iter iter_;
};
std::unique_ptr<concept> concept_ptr_;
public:
bool operator==(PolymorphicValueIterator const &r) const {
return concept_ptr_->is_equal(r.concept_ptr_->get_details());
}
bool operator!=(PolymorphicValueIterator const &r) const {
return not concept_ptr_->is_equal(r.concept_ptr_->get_details());
}
PolymorphicValueIterator &operator++() {
concept_ptr_->invoke_next(1);
return *this;
}
value_type& operator*() const {
return concept_ptr_->invoke_deref();
}
template<class Iter>
PolymorphicValueIterator(Iter iter)
{
concept_ptr_ = std::make_unique<model<Iter>>(iter);
}
PolymorphicValueIterator(PolymorphicValueIterator const& r)
: concept_ptr_(r.concept_ptr_->clone())
{}
PolymorphicValueIterator& operator=(PolymorphicValueIterator const& r)
{
concept_ptr_ = r.concept_ptr_->clone();
return *this;
}
};
template<class Iter>
auto makePolymorphicValueIterator(Iter iter)
{
using iter_value_type = typename std::iterator_traits<Iter>::value_type;
using value_type = type_of_value_t<iter_value_type>;
return PolymorphicValueIterator<value_type>(iter);
}
// a test
void do_orange_things(PolymorphicValueIterator<Orange> first, PolymorphicValueIterator<Orange> last)
{
while(first != last) {
std::cout << "Orange\n";
++first;
}
}
int main()
{
std::vector<Orange> vo {
Orange(), Orange()
};
std::map<int, Orange> mio {
{ 1, Orange() },
{ 2, Orange() },
{ 3, Orange() }
};
std::cout << "vector:\n";
auto first = makePolymorphicValueIterator(vo.begin());
auto last = makePolymorphicValueIterator(vo.end());
do_orange_things(first, last);
std::cout << "\nmap:\n";
first = makePolymorphicValueIterator(mio.begin());
last = makePolymorphicValueIterator(mio.end());
do_orange_things(first, last);
}

std::set - like function object support in my container

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

find int inside struct with find_if for std::list with structs

How can I use find_if with a std::list if the list contains structs? My first pseudo code attempt at this looks like this:
typename std::list<Event>::iterator found =
find_if(cal.begin(), cal.last(), predicate);
The problem here is that the predicate is not directly visible in the list but inside event.object.return_number(). How am I suppose to refer to an int that is nested inside the struct and needs a get method to be accessed.
You can use a functor class (which is like a function, but allows you to have state, such as configuration):
class Predicate
{
public:
Predicate(int x) : x(x) {}
bool operator() (const Cal &cal) const { return cal.getter() == x; }
private:
const int x;
};
std::find_if(cal.begin(), cal.end(), Predicate(x));
In C++0x, which your compiler probably already partially implements, you can do the following:
find_if(cal.begin(), cal.last(), [&](const Event& e)
{
return e.object.return_number() == value_to_find;
});
You set up your predicate something like this:
struct IsEventObjectReturnNumber
{
int num;
explicit IsEventObjectReturnNumber( int n ) : num( n ) {}
bool operator()(const Event & event ) const
{
return event.object.return_number() == num;
}
};
std::list<Event>::iterator = std::find_if(cal.begin(), cal.end(), IsEventObjectReturnNumber(x));
The (not so simple, but) simplest way (in the absence of C++11) is a custom comparator:
struct CompareMyStruct {
int n_;
CompareMyStruct(int n) : n_(n) { }
bool operator()(const Event& a) const {
return a.object.return_number() == n_;
}
};
typename std::list<Event>::iterator found =
find_if(cal.begin(), cal.last(), CompareMyStruct(123));

Generic object carrier class - C++

I need to create a generic object carrier class. I came up with something simple like
template<typename T>
class ObjectCarrier
{
public:
const T& item() const
{
return item_;
}
void setItem(T& item)
{
item_ = item;
}
private:
T item_;
};
This works well when T has got a default constructor (parameterless). Things gets complicated when T has parameterized constructors. So I rewrote the class like
template<typename T>
class ObjectCarrier
{
public:
const T& item() const
{
return *item_;
}
void setItem(T& item)
{
item_ = new T ( item );
}
private:
T* item_;
};
Changed the item_ variable to T* and created a new instance using the copy constructor of T. Again this worked well until T is a pointer type. I mean ObjectCarrier<Foo*> won't work.
I am wondering how can I design this class so that it works for almost all kind of types. I think I may need to create a traits type specialized for pointers. But unfortunately, I am not able to make that work.
Any help would be great.
The above approaches are way way too complicated. Keep it simple, and just solve the constructor arg problem by using template constructors. Don't use pointers, they will create object lifetime and copying headaches.
Here's an implementation I use a lot. The template constructors will forward arguments for things directly on to the nested object which is convenient. The operator T& values let you pass carrier<T> to functions that take a type T, without expensive copying. You can wrap objects that take up to two arguments with this code.
/* A wrapper of type T */
template <typename T>
struct carrier {
carrier() {}
template <typename A1> carrier(const A1& a1) : value(a1) {}
template <typename A1, typename A2> carrier(const A1& a1, const A2& a2) : value(a1, a2) {}
operator T&() { return value; }
operator const T&() const { return value; }
T value;
};
You can use it like this:
const carrier<point> p1(10,10); // make p1 const to stop people changing it
showPoint(p1); // calls a function that expects a point,
showPoint(p1.value); // access the point directly
You can use template specialization for the T* type and rewrite the methods to suite pointers. You can do something like:
template<typename T>
class ObjectCarrier<T*>
{
public:
const T* item() const
{
return item_;
}
void setItem(T* item)
{
item_ = item;
}
private:
T* item_;
};
There is a design patern that is possibly relevant to this - Memento.
A bit off topic, but bear in mind that as soon as you start newing objects up inside your class, you'll need a way to manage the memory. I'd suggest using an std::auto_ptr at the least. You'll also need to provide a copy constructor and an assignment operator, when using std::auto_ptr.
It might be possible to hold the object by value and still defer its construction with the use of placement new and something like the following:
#include <iostream>
#include <cassert>
template <class T>
class ObjectCarrier
{
public:
ObjectCarrier(): ref(0) {}
ObjectCarrier(const ObjectCarrier& other): ref(0)
{
set_data(other.ref);
}
~ObjectCarrier()
{
clear();
}
const ObjectCarrier& operator = (const ObjectCarrier& other)
{
if (other.empty())
clear();
else
set_data(other.ref);
return *this;
}
void set(const T& value)
{
set_value(value);
}
const T& get() const
{
assert(!empty() && "No object being carried");
return *ref;
}
bool empty() const
{
return ref == 0;
}
void clear()
{
if (!empty()) {
ref->~T();
ref = 0;
}
}
private:
char data[sizeof(T)];
T* ref;
void set_value(const T& value)
{
if (!empty()) {
*ref = value;
}
else {
ref = new (data) T(value);
}
}
void set_data(const T* value)
{
if (value) {
set_value(*value);
}
}
};
int main()
{
ObjectCarrier<int> i;
ObjectCarrier<int> j(i);
i = j;
i.set(10);
std::cout << i.get() << '\n';
j = i;
i.set(20);
std::cout << i.get() << ' ' << j.get() << ' ' << ObjectCarrier<int>(i).get() << '\n';
}
However, I would somewhat question the usefulness of this class. Perhaps the only purpose it could have, would be to act as Boost.Optional.
But if you don't want the class to be able to not hold a value, just give it a parametrized constructor:
template<typename T>
class ObjectCarrier
{
public:
ObjectCarrier(const T& value = T()):
item_(value)
{
}
const T& item() const
{
return item_;
}
void setItem(T& item)
{
item_ = item;
}
private:
T item_;
};
(It's just that this class seems rather useless, unless perhaps as a facade for code that expects variables to have item and setItem methods, rather than, say, an assignment operator.)
boost::optional does something very similar to this (also boost::any, but nevermind).
You can check out how its implemented at: http://cplusplus.co.il/2009/12/04/boost-optional-and-its-internals/ and don't worry - it's pretty straightforward.