Custom comparator for custom class, just like STL - c++

I have a custom class Binary search Tree. I want to pass a comparator class as an argument (with default being std::less). Most of the answers I searched use the STL objects and then pass their custom comparators. I want something different.
// Tree class
template <class T,class Compare = less<T>>
class Tree
{
struct TreeNode
{
T data;
struct TreeNode * left;
struct TreeNode * right;
};
public:
void insert(T);
};
// Custom comparator class
template <class T>
class CustomCompare
{
public:
bool compare(const T&, const T &);
};
template<class T>
bool CustomCompare<T>::compare(const T & a, const T &b)
{
cout << "calling custom comparator";
return a<b;
}
// inserting in tree
template<class T,class Compare>
void Tree<T,Compare>::insert(T val)
{
// HOW DO I CALL COMPARE HERE? I tried this
if (compare(val->data , treeNode->data)) /// does not work.
// I get error - use of undeclared identifier compare.
//IF I DO THIS, I get error - expected unqualified id
Compare<T> x; // cannot create instance of Compare
// IF I DO THIS< I can create instance of Compare but cannot call function compare.
Compare x;
x.compare(....) -- Error no member named compare in std::less
}
I cannot make the CustomCompare::compare static as I want the code to work for std::less too.
I hope the question is clear.
Note: I know I can overload operator < for the classes that will be using it. I am preparing for the situation in case source code of those classes is not available

std::less has the following function to compare objects.
bool operator()( const T& lhs, const T& rhs ) const;
If you want to use a custom compare class to be an equal substitute, you have to have such a function in that class too.
Then, you would use it as:
if (compare()(val->data , treeNode->data))

Related

Implement a function with the argument of both types const T & and T&&

I am doing humble attempts to implement some specific BST with the interface compatible with std::set and the more attempts I do the more questions I have.
For example, one of the questions is how to minimize code duplication while implementing two overloaded versions of insert method:
std::pair<iterator, bool> insert(const value_type & value)
and
std::pair<iterator,bool> insert(value_type&& value);
Currently I implemented the first overload that internally calls a private method FindNodeByKey:
template<class T, class Compare = std::less<>, class Allocator = std::allocator<T>>
class my_set
{
...
private:
template <class Key>
Node * FindNodeByKey(const Key & key) const
{
Node * x = m_root;
//walk down the tree
while (x != nullptr)
{
if (m_comp(key, x->value))
{
x = x->left;
}
else if (m_comp(x->value, key))
{
x = x->right;
}
else
{
return x;
}
}
return nullptr;
}
Comparer m_comp;
}
where m_comp is a Comparer instance, Node is a structure containing BST links and the value of type T, Key is any type the Comparer supports and in particular value_type.
1) What is the optimal way to implement FindNodeByKey with the parameter of type Key && (for using with the second insert overload)? Is there a way to avoid its code duplication?
2) And should I pass Key && to the comparer?
3) Also honestly I do not quite understand why I use std::less<>, but std::set uses std::less<T> as the default comparer.
EDIT1:
value_type is not guaranteed to have copy constructor (be copyable).
You just have both overloads forward to an implementation template:
template<class T, class Compare = std::less<>, class Allocator = std::allocator<T>>
class my_set {
public:
std::pair<iterator, bool> insert(const value_type& value) {
return insert_impl(value);
}
std::pair<iterator, bool> insert(value_type&& value) {
return insert_impl(std::move(value));
}
private:
template <typename V>
std::pair<iterator, bool> insert_impl(V&& value)
{
// all the logic here, just eventually std::forward the value into the right
// spot. We know at this point that V is either const value_type& or value_type
}
};
You definitely shouldn't have a Node * FindNodeByKey(Key&& key) const overload. It doesn't make sense as you are not using the parameter key to make a copy of it. You are just using it to pass it (multiple times) to m_comp (which in turn doesn't make a copy of it).
You generally want const T& x and T&& x overloads when your function needs to make one and only one copy of x. Then you can optimize this in the case where the value passed is a temporary so instead of the copy you do a move.
As for your insert, yes here you can implement both overloads because insert fits perfectly into the above category. And both overloads should call FindNodeByKey(const Key&)
You can eliminate having to implement one of your overloads by simply calling the other overload from it:
std::pair<iterator, bool> insert(const value_type & value)
{
return insert(value_type(value));
}
As long as your value_type has a copy constructor, this will create a temporary copy of value, and then call the overload of insert that takes an rvalue reference.

Overloading operator[] for a container class with template objects

First of all, I have a template class that looks like this:
template <typename T>
class Configurable
{
public:
//protected:
T var_value;
std::string var_name;
std::string var_type;
Configurable()
: var_value(0), var_name("unnamed"), var_type("undefined")
{}
Configurable( T v_value, std::string v_name, std::string v_type )
: var_value(v_value), var_name(v_name), var_type(v_type)
{}
std::string get_name() {return var_name;}
};
I also have a container class named Config which has a couple of different Configurable lists for storage of Configurable ints, bools and floats. I want to overload the [] operator of Config so that it returns a Configurable with the given name (regardless of the type) from one of the lists, but this doesn't seem to work:
template <typename T>
Configurable<T>& operator[] ( const std::string v_name_arg );
The compiler returns an error of 'no match for operator[]'. So my question is - how can I make this work? Is it even possible to do it using templates or should I find a different approach with inheritance?
EDIT: Sorry for all the confusion. Here's the container class I'm talking about:
class Config
{
public:
//private:
std::list < Configurable<int> > list_int;
std::list < Configurable<float> > list_float;
std::list < Configurable<double> > list_double;
std::list < Configurable<bool> > list_bool;
//public:
Config(){}
template <typename T>
Configurable<T>& operator[] ( const std::string &v_name_arg );
};
The problem with declaring the templated operator[] without any argument that depends on the template parameter is that the compiler cannot determine the type T from a call in the form config["name"].
One solution, considering code readability, would be changing the operator[] to a method such as:
template <typename T>
Configurable<T>& get ( const std::string v_name_arg );
Then, the call should be written like:
config.get<int>("name")
Also, consider passing the string by reference (const std::string&) to avoid unnecessary copies of a std::string passed to the method/operator.
As described above, it's a syntax error.
WHen you write:
template <typename T>
Configurable<T>& operator[] ( const std::string v_name_arg );
You try to define a free standing operator[] as if it would be a free standing function.
But according to your explanations, operator[] should be a member of your container Config.
So the its definition should look somewhat like:
template <typename T>
class Config {
//...
public:
Configurable<T>& operator[] (const std::string v_name_arg) { /* return a ref to a Configurable */ };
};
With such a definition, the stuff compiles, and you can use it for example with :
int main()
{
Configurable<int> c;
Config<int> cfg;
auto a = cfg["test"];
}

no overloaded function takes 2 arguments(functors)

I run into a probles while trying to implement custom comparator support for my Heap data structure
Here's how I want it to look like:
template <class T, class Pred = std::less<T>>
class ConcurrentPriorityQueue {
private:
template <class T>
class Node
{
private:
T data;
bool operator < (const Node<T>& t) {
return Pred(data, t.data);
}
};
};
And this is a compare functor I want to use:
struct comp {
bool operator () (const std::pair<int, fn_type> &p1,
const std::pair<int, fn_type> &p2) const{
return p1.first < p2.first;
}
};
ConcurrentPriorityQueue<std::pair<int, fn_type>, comp> fqueue;
Everything looks pretty much right for me, however I get Error
Error 2 error C2661: 'ThreadPool::comp::comp' : no overloaded function takes 2 arguments c:\users\usr\documents\visual studio 2013\projects\secondtask\queue.hpp. Could you please help me out with this.
Pred refers to a type, not an instance of that type.
Currently you are trying to invoke a constructor of type Pred when doing Pred(data, t.data), you will first have to create an instance of Pred to be able to call a matching operator() (...) on it.
The below example creates a temporary instance of type Pred, and then calls its operator();
return Pred () (data, t.data); // 1) create a temporary instance of `Pred`
// 2) call its operator() with `data` and `t.data`

Template with comparator function with custom parameter

I am working on a data structure and I want it to have comparison function, that can be passed to the constructor, the same way as stl data structures (set, queue, etc.) work. I also want a default function provided in the constructor.
The problem is, that the query to the structure is a function template, that takes custom type as a parameter. But I don't know how to provide the default comparison function if I don't know what type the query will be. Is there a way to do this?
This works if the Query is the same as the NodeType (Query is useless in this example):
template<class NodeType, class Query = NodeType>
inline float eucDistance(const Query * p1, const NodeType * p2) {
...
}
template<class NodeType, typename Comp = decltype(eucDistance<NodeType>)>
class KDTree {
Comp* distance;
public:
KDTree(Comp comaprator = &eucDistance<NodeType>) : distance(comaprator) {
}
template<class Query = NodeType>
NodeType * nearestNeighbor(const Query *query) {
...
float tmp = distance(query, sth);
//I want something like distance<NodeType, Query>(query, sth);
...
}
}
But I would like to do something like this:
class Point; //some type that the tree contains
KDTree<Point> tree;
Point p1;
Point *p = tree.nearestNeighbor(&p1); //this works with the given example
...
vec3 vec = ...; //some different type as a query
p = tree.nearestNeighbor<vec3>(vec); // <-- this is what I would like to do
template<typename Query, typename NodeType = Query>
inline float eucDistance(const Query * p1, const NodeType * p2) {
...
}
class KDTree {
public:
template<typename Query = NodeType, typename Comparator>
NodeType * nearestNeighbor(const Query *query, Comparator comp) {
...
float tmp = comp(query, sth);
...
}
}
This code takes in the comparator at the member function level due to which it can take on different type of nodes. Also the template type deduction will work; so instead of calling function like thus comp<T>(a, b); just comp(a, b) should work.
The main difference between your code and C++ standard library functions (algorithms) taking a comparator argument is that they don't enforce them to be pointers or rather C-style pointer to functions. Instead they use functors.
Take std::for_each which calls a functor for the elements passed; it takes a functor thus
template <typename InputIter, typename UnaryFunc>
UnaryFunc std::for_each(InputIter first, InputIter last, UnaryFunc func)
{
for (; first != last; ++first)
func(*first);
return func;
}
If you notice, there're no pointers. It calls func with the operator (); the beauty of this is that it works for both C-style function pointers and also C++ style functors i.e. a struct with an operator() defined. Also notice that the template type used for the functor is agnostic of what type the functor accepts.
You should use polymorphic functor instead of plain function, for example
struct eucDistance
{
float operator()(Point, Point) const;
float operator()(vec3, Point) const;
...
};
BTW, you really should take a look at Boost.Geometry and it's R-tree design.

Creating a template predicate class requiring a pointer to method function, and ensuing compiler errors

I'm building a series of predicates that duplicate lots of code, and so are being changed into a single template function class based on the std::unary_function. The idea is that my class interface requires methods such as Element_t Element() and std::string Name() to be defined, so the predicate template arguments are the object type and a value type to which comparison will be made as follows:
// generic predicate for comparing an attribute of object pointers to a specified test value
template <class U, typename R>
class mem_fun_eq : public std::unary_function <U*, bool> {
private:
typedef R (U::*fn_t)();
fn_t fn;
R val;
public:
explicit mem_fun_eq (fn_t f, R& r) : fn(f), val(r) { }
bool operator() (U * u) const {
return (u->*fn)() == val;
}
};
Thus, if I have:
class Atom {
public:
const Element_t& Element() const { return _element; }
const std::string& Name() const { return _name; }
};
I would like to perform a search on a container of Atoms and check for either the Name or Element equality using my template predicate like so:
typedef std::string (Atom::*fn)() const;
Atom_it it = std::find_if( _atoms.begin(), _atoms.end(), mem_fun_eq <Atom, std::string> ((fn)&Atom::Name, atomname));
but compiling this returns the following error on the std::find_if line:
error: address of overloaded function with no contextual type information
Also, trying to form the same predicate for a check of the Element() as such:
typedef Atom::Element_t& (Atom::*fn)() const;
Atom_it it = std::find_if(_atoms.begin(), _atoms.end(), mem_fun_eq <Atom, Atom::Element_t> ((fn)&Atom::Element, elmt);
creates a different error!
error: no matching function for call to ‘mem_fun_eq<Atom, Atom::Element_t>::mem_fun_eq(Atom::Element_t& (Atom::*)()const, const Atom::Element_t&)’
note: candidates are: mem_fun_eq<U, R>::mem_fun_eq(R (U::*)(), R&) [with U = Atom, R = Atom::Element_t]
note: mem_fun_eq<Atom, Atom::Element_t>::mem_fun_eq(const mem_fun_eq<Atom, Atom::Element_t>&)
Firstly, am I reinventing the wheel with this predicate? Is there something in the STL that I've missed that does the same job in a single class? I can always break the predicate down into several more specific ones, but I'm trying to avoid that.
Secondly, can you help me with the compiler errors?
I don't know of any easy way to do this using the bits provided with the STL. There is probably some clever boost way, using iterator adapters, or boost::lambda, but personally I wouldn't go that way.
Obviously C++0x lambdas will make all this easy.
Your problem is attempting to cast a function like this:
const std::string&(Atom::*)()
into a function like this:
std::string (Atom::*)()
If you replace your typedef R (U::*fn_t)(); with typedef const R& (U::*fn_t)() const; then it should work.
The following avoids this problem and also provides type inference so that you can just write mem_fun_eq(&Atom::Name, atomname). It compiles for me, although I haven't tested it.
template<typename U, typename R, typename S>
class mem_fun_eq_t : public std::unary_function<U const*, bool>
{
private:
R (U::*fn_)() const;
S val_;
public:
mem_fun_eq_t(R (U::*fn )() const, S val) : fn_(fn), val_(val){}
bool operator()(U * u)
{
return (u->*fn_)() == val_;
}
};
template<typename U, typename R, typename S>
mem_fun_eq_t<U, R, S> mem_fun_eq(R (U::*fn)() const, S val)
{
return mem_fun_eq_t<U, R, S>(fn, val);
}
Have you thought of trying to mix in a mem_fun_ref or mem_fun object in place of the member function call?
Basically, you call on mem_fun to create an object that accepts two arguments T* and a template argument to the function A if it has one (or void if it doesn't). Hence you combine it like so:
template<typename MemFunc, typename CompareType, typename T>
struct MyPredicate{
MyPredicate(MemFunc _functionObj, CompareType _value)
: m_Value(_value),
m_Function(_functionObj){}
bool operator()(const T &_input){
return m_Value == m_Function(_input);
}
private:
MemFunc m_Function;
CompareType m_Value;
};
Edit:
Ok, that's not completely working so why not have:
struct NamePred: binary_function<Atom*,string,bool>{
bool operator()(Atom *_obj, string _val){
return _obj->Name() == _val;
};
};
then use bind2nd
find_if( atoms.begin(), atoms.end(), bind2nd( NamePred, "yo" ) );