Functor and templates - c++

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?

Related

table of uniquely named objects

I would like to tabulate
struct object {
std::string unique_name;
some_type more_data;
other_type member_functions() const; // many such member functions
};
using the unique_name as index. Unfortunately, I cannot use
using object_table = std::unordered_set<object>;
since there is no way to search for an object given a name, as object_table::find() only allows for search keys of type object:
class objects {
object_table _table;
public:
object const&operator[](std::string const&name) const
{
// cannot be implemented using object_table::find()
}
};
So what can I do?
My awkward solution so far was
using object_table = std::unordered_map<std::string, some_type>;
struct object : object_table::value_type
{
std::string const&name() const { return first; }
other_type member_functions() const;
private:
using object_table::value_type::first;
using object_table::value_type::second;
};
class objects {
object_table _table;
public:
object const&operator[](std::string const&name) const
{
auto it = _table.find(name);
if(it == _table.end())
throw runtime_error("cannot find object '"+name+'\'');
return *static_cast<const object*>(std::addressof(*it)); // is cast legal?
}
};
This works at the price for patching object together in an cumbersome way from a std::pair<std::string, some_type>.
Since your names are unique per object you can just use the hash of unique_name as the hash for your object. Using
namespace std
{
template<> struct hash<object>
{
typedef object argument_type;
typedef std::size_t result_type;
result_type operator()(argument_type const& o) const noexcept
{
return std::hash<std::string>{}(o.unique_name);
}
};
}
bool operator ==(const object& lhs, const object& rhs)
{
return lhs.unique_name == rhs.unique_name;
}
The lets you write the lookup code like
using object_table = std::unordered_set<object>;
class objects
{
object_table _table;
public:
object const&operator[](std::string const&name) const
{
if (auto it = object_table.find(object{name}); it != object_table.end())
return *it
else
throw();
}
};
This does require that object be constuctable from a singlestd::string and that it is used to initialize unique_name.

Define Return value as * or & based on custom Iterator<T>

Updated
I am working on some container code in an environment where I the STL is not available to me. I am trying to generalize my iterators to reduce code duplication. I've encountered a case where I have a container that can contain Objects or pointers to Objects. I am having a compilation problem when trying to compile the following (contrived) code:
struct Object
{
};
template<typename Container, typename T>
struct IteratorBase
{
IteratorBase( Container * container, T curr ) : _container( container ), _curr( curr ) { }
Container * _container;
T _curr;
T & GetValue() const { return _curr; }
void Invalidate() { _curr = NULL; }
};
template<typename T>
struct Container
{
typedef typename T * Type;
typedef IteratorBase<Container<T>, Type> Iterator;
Iterator GetIterator() { return Iterator( this, storage ); }
T storage[10];
};
int main(int argc, char* argv[])
{
Container<Object> containerByAddress;
const Object* pA = containerByAddress.GetIterator().GetValue();
return 0;
}
The error is
error C2440: 'return' : cannot convert from 'Object *const ' to 'Object *&'
while compiling class template member function 'Object &IteratorBase<Container,T>::GetValue(void) const'
So I have made some changes to change how the value is returned by deducing the type of T using the following:
template<typename T>
struct DetermineReturnType
{
typedef T & ReturnType;
};
template<typename T>
struct DetermineReturnType<T*>
{
typedef T * ReturnType;
};
template<typename Container, typename T>
struct IteratorBase
{
IteratorBase( Container * container, T curr ) : _container( container ), _curr( curr ) { }
Container * _container;
T _curr;
typedef typename DetermineReturnType<T>::ReturnType ReturnType;
ReturnType GetValue() const { return _curr; }
void Invalidate() { _curr = NULL; }
};
Now my iterator uses & or * based on T.
But my question is - is this a reasonable solution? is there something I can do to fix this?
Please note I cannot use STL, Boost, nor latest version of C++ as this is an embedded system some years old.
Thanks for any insight.
The problem is that GetValue() is declared const but you are returning a non-const reference to a member variable. If the compiler allowed you do to this you would be able to modify the member variable in a possibly const qualified instance of the iterator. You can solve this pretty easily by providing both a const and non-const version of GetValue(). The compiler will choose the appropriate version based on the CV qualifiers of the iterator instance.
T const& GetValue() const { return _curr; }
T& GetValue() { return _curr; }
Unfortunately this is not likely going to get you the real behavior you are looking for. You really should not be returning a reference here as it will only allow you to change the element inside iterator rather than the element in the container. To get where you want you'll need to change more than just the GetValue implementation and redesign your iterators to work with the elements in the container rather than maintaining it locally.
Below is a basic example of how you might approach this. It returns a reference to the element in the container allowing you to modify the container through the iterator. Since I don't have a full version of your Container I'm using naked arrays but the visible end result should be easy to grasp.
#include <iostream>
struct Object { };
template<typename T>
struct IteratorBase
{
IteratorBase(T* initialPtr) : _curr(initialPtr) {}
T* _curr;
T const & GetValue() const { return *_curr; }
T& GetValue() { return *_curr; }
void next() { ++_curr; }
void prev() { --_curr; }
};
int main()
{
Object a, b, c, d, e;
Object *objects[] = { &a, &b, &c, &d, &e };
IteratorBase<Object*> it(objects);
for (int i = 0; i < sizeof(objects) / sizeof(*objects); i++)
{
std::cout << it.GetValue() << "\n";
it.GetValue() = NULL;
it.next();
}
it = IteratorBase<Object*>(objects);
for (int i = 0; i < sizeof(objects) / sizeof(*objects); i++)
{
std::cout << it.GetValue() << "\n";
it.next();
}
}

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

Custom comparator for multiset that contains pointers to objects

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.

generic lookup method?

I'd like a generic method for retrieving the data from a vector.
I have a the following class and vector:
class myClass
{
public:
myClass(int myX, float myZ, std::string myFoo)
: x ( myX )
, z ( myZ )
, foo ( myFoo )
{
}
myClass()
{
}
int x;
float z;
std::string foo;
} ;
std::vector < myClass > myVector;
(The complete code can be seen here: http://codepad.org/iDD1Wme5 )
In this example I would like to be able to retrieve objects in the vector based on the "z" or "foo" members without having to write another 2 functions similar to "FindDataById".
Is that possible?
You can use a template and pointer to member.
typedef vector<myClass> myVector;
template<typename T>
bool FindDataById(const T &id, T myClass::* idMember, myClass &theClass,
const myVector &theVector)
{
for(myVector::const_iterator itr = theVector.begin(); itr != myVector.end();
++itr){
if((*itr).*idMember == id){
theClass = *itr;
return true;
}
return false;
}
Then call using, e.g.,
FindDataById(string("name"), &myClass::foo, theClass, theVector)
FindDataById(5, &myClass::x, theClass, theVector)
FindDataById(5.25f, &myClass::z, theClass, theVector)
Or, go with the find_if idea:
template<typename T>
struct Finder {
T val_;
T myClass::* idMember_;
Finder(T val, T myClass::* idMember) : val_(val), idMember_(idMember) {}
bool operator()(const myClass &obj) { return obj.*idMember_ == val_; }
};
And use:
find_if(theVector.begin(), theVector.end(), Finder<string>("name", &myClass::foo))
find_if(theVector.begin(), theVector.end(), Finder<int>(5, &myClass::x))
find_if(theVector.begin(), theVector.end(), Finder<float>(3.25f, &myClass::z))
See the answer of MSalters for a way to deduce the template argument automatically.
std::find_if has already been suggested, but without a code sample, so here's a more detailed version:
Define two functors to identify the object you're interested in:
struct z_equals {
z_equals(float z) : z(z) {}
bool operator()(const myClass& obj)
return z == obj.z;
}
float z;
};
struct foo_equals {
foo_equals(const std::string& foo) : foo(foo) {}
bool operator()(const myClass& obj)
return foo == obj.foo;
}
const std::string& foo;
};
And now, to search for elements where z == 42.0f, or foo == "hello world":
std::find_if(myVector.begin(), myVector.end(), z_equals(42.0f));
std::find_if(myVector.begin(), myVector.end(), foo_equals("hello world"));
You can use functors and pass it to your lookup method. That I mean is, define class which will overload bool operator( vectorElement element) and within this operator you will choose method how do you want to lookup the values.
template <typename T>
class ILookUp
{
bool operator( vector<T> elem)
{
if (elem == something)
return true;
false;
}
};
class VectorStorage
{
std::vector<Elements> lookup( ILookUp<Elements> lookup)
{
.....
if ( lookup(elem))
{
//add element to vector or whatever.
}
.....
return result;
}
.....
}
It might be worth taking a look at std::find defined in algorithm and boost::lambda
Without lambda's you'd need to write some predicates, or at least instantiate them:
template
struct member_select : public std::unary_function
{
T t;
T U::* m_u;
member_select(T const& t, T U::* m_u) : t(t), m_u(m_u) {}
bool operator()(U const& u) const { return u.*m_u == t; }
};
template
member_select make_member_select(T const& t, T U::* m_u)
{
return member_select(t, m_u);
}
Use: std::find_if(..., make_member_select("x", &myClass::foo));