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.
Related
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.
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))
I'm having a custom list class and would like to support operations using the "comparison operator" known from the STL. For example:
std::list<MyClass> d;
struct not_key {
not_key( std::string const& str) : str_(str) {}
bool operator( MyClass& elem ) {
return !elem.findThatThing();
}
std::string str_;
};
not_key comp("value");
d.remove_if( comp );
mylist<MyClass> e(d);
e.filter( comp );
And I'm struggling about the signature of a method which accepts these "general" comparison operators. Since all of them have a different type and I don't want static member functions. How can I add a method to my class which accepts the comparison operators?
Thank you very much! :)
If you mean you want to know the signature of mylist::filter you would probably just make it a template with Pred or similar as the type.
template< typename T >
class mylist
{
public:
template< typename Pred >
void filter( Pred pred )
{
// implement, calling pred(elem) for each element or pred(*iter)
}
};
Note that you can pass a free function into that template function, and in C++11 you'll be able to pass in a lambda.
If you want something that isn't a template (other than on the element type) you can use a boost::function (or std::function)
The standard functions (such as std::sort) use a template argument which is deduced to be the type of your comparison function-like object:
template <class UnaryPredicate>
void filter(UnaryPredicate func) {
// Call it like:
func(something);
}
Now UnaryPredicate will be deduced to be the type of whatever function-like object you pass to it. UnaryPredicate makes more sense than calling it a comparison function since it only takes a single argument. A comparison function would typically take two arguments and compare them.
Alternatively, you could take a std::function<bool(const MyClass&)>:
void filter(std::function<bool(const MyClass&)> func) {
// Call it like:
func(something);
}
The signature should be:
bool operator()(Myclass const & elem) const
I have a series of several similar structures, e.g.,
map<key1, attr1>; map<key2, attr2>; ...,
meanwhile, in correspondence, a series of array,
// JUST TO SHOW THE IDEA, NOT SYNTAX CORRECT
class {key_1; attr_1;} array [#]; class {key_2; attr_2;} array [#]; ...,
and keyX and key_X share the similar structure, as well as attr, e.g.
struct key1 {int k1;}; class key_1 {int k_1;};
struct key2 {int k1; int k2;}; class key_2 {int k_1; int k_2;};
...
struct attr1 {int a1; int a2;}; class attr_1 {int a_1; int a_2;};
I need to write a function, like overloading the assignment operator, to convert the data from map_series to the other, and vice versa.
So instead of doing it map by map, key by key, and int by int, is there some template-wise way to do it, so the code would be generic,or save more lines of code? What could be the smart way to do this?
EDIT 1:
Unfortunately, one constraint due to our legacy system, the type convertion between struct, e.g. key1, key_1, does not work as C++ primitives, so a conversion function also have to be provided.
EDIT 2:
inspired by J.N. answer, is it possible to have something like:
template <class KeyMap, class ValueMap, class KeyArr, class ValueArr> void convert (map<KeyMap, ValueMap>, class {KeyArr, ValueArr} array[]){};
how to generlize the conversion for key and attr? like
template <class KeyMap, class KeyArr> void convert_key(KeyMap, KeyArr){}
Ok so let's suppose we have this:
map<KeyTypeM, ValueTypeM> m1;
struct Type1 {
KeyTypeS Key;
ValueTypeS Value;
};
Let's define the conversion function first:
Type1 ConvType1(const KeyTypeM& key, const ValueTypeM& value)
{
Type1 result;
result.Key = f(key); // user dependent
result.Value = f(value); // user dependent
return result;
}
Then, in C++, you can't return arrays. Actually you usually don't work with array, people usually prefer std::vector. (If you really need an array then you need to allocate it and return a pointer to it or wrap it in a smart pointer)
Then it is enough to browse the values in the map and push them into the vector:
vector<Type1> ConvertType1(map<KeyTypeM, ValueTypeM>& input)
{
vector<Type1> result;
for (auto& pair : input) // assumes C++11
result.push_back( ConvType1(pair.first, pair.second) );
return result;
}
note: if you do not have a C++11 compiler, use:
for (map<KeyTypeM, ValueTypeM>::iterator it = m.begin(); it != m.end(); ++it)
result.push_back( ConvType1(it->first, it->second) );
That will do the job for ONE map and one type. Now we can generalize the conversion function by using templates:
template <class OutType, class KeyType, class ValueType, class Converter>
vector<OutType> Convert(map<KeyType, ValueType>& input, Converter conv)
{
vector<OutType> result;
for (auto& pair : input)
result.push_back( conv(pair.first, pair.second) );
return result;
}
And use it like this:
auto v1 = Convert<Type1>(m1, &ConvertType1);
auto v2 = Convert<Type2>(m2, &ConvertType2);
...
You could go further by creating a list of types to convert using boost::mpl but that should be in another question.
EDIT: generalize the conversion of the types
As you mentioned, there's no generic way to convert the types, we'll have to write all the conversion functions. So the only thing we can do is make it more elegant by implementing implicit conversion operators like this:
struct KeyTypeM
{
... // normal members
operator KeyTypeS() const
{
// do the conversion here
}
};
// suppose we have the same for ValueTypeM and ValueTypeS
// We can now use a single convert function:
template <class OutType, class KeyTypeM, class ValueType M>
OutType ConvertToStruct(const KeyTypeM& key, const ValueTypeM& value)
{
OutType result;
result.Key = key; // will call the implicit conversion
result.Value = value;
return result;
}
This simplifies our conversion function (updated to take into account the array)
template <class OutType, class KeyType, class ValueType>
void Convert(map<KeyType, ValueType>& input, OutType out[])
{
// out must have been initialized to a proper size to hold all the elements.
unsigned cursor = 0;
for (map<KeyTypeM, ValueTypeM>::iterator it = m.begin(); it != m.end(); ++it, ++cursor)
out[cursor] = ConvertToStruct<OutType>(it->first, it->second);
}
EDIT 2: We can use std::pair to generalize the array structure:
template <class OutType, class KeyTypeM, class ValueType M>
OutType ConvertToStruct(const KeyTypeM& key, const ValueTypeM& value)
{
OutType result;
result.first = key; // will call the implicit conversion
result.second = value;
return result;
}
template <class OutKey, class OutValue, class KeyType, class ValueType>
void Convert(map<KeyType, ValueType>& input, std::pair<OutKey, OutValue> out[])
{
// out must have been initialized to a proper size to hold all the elements.
unsigned cursor = 0;
for (map<KeyTypeM, ValueTypeM>::iterator it = m.begin(); it != m.end(); ++it, ++cursor)
out[cursor] = ConvertToStruct<OutType>(it->first, it->second);
}
// Use this way:
std::pair<OutKey, OutValue> arr[m.size()];
Convert(m, arr);
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" ) );