Pass generic template class as functor parameter - c++

I want to improve the following code snippet:
THNNetIPInfoIter last = std::unique(fist, end, HNInfoIPComparator());
where currently HNInfoIPComparator() is implemented as following:
// equal comparator
class HNInfoIPComparator
{
public:
bool operator()(const THNNetIPInfo &a, const THNNetIPInfo &b);
bool operator()(const SDK::TIPAddressDescription &a, const SDK::TIPAddressDescription &b);
bool operator()(const THNNetIPInfo &a, const SDK::TIPAddressDescription &b);
bool operator()(const SDK::TIPAddressDescription &a, const THNNetIPInfo &b);
};
The reason for this comparator definition is that it might be used with another STL algorithms, like std::set_difference and should handle case when ranges has different types.
The problem is that I have to write huge amount of very similar comparators and it is easy to be entangled with which comparator to use.
I want to write the following snippet:
template<typename SDKClass, typename IDLClass>
class equal {
public:
bool operator()(const IDLClass &a, const IDLClass &b) {
if (strcmp(a.ipaddr.in(), b.ipaddr.in())) {
return false;
}
return true;
}
bool operator()(const SDKClass &a, const SDKClass &b) {
if (strcmp(a.ip_address().c_str(), b.ip_address().c_str())) {
return false;
}
return true;
}
bool operator()(const IDLClass &a, const SDKClass &b) {
if (strcmp(a.ipaddr.in(), b.ip_address().c_str())) {
return false;
}
return true;
}
bool operator()(const SDKClass &a, const IDLClass &b) {
if (strcmp(a.ip_address().c_str(), b.ipaddr.in())) {
return false;
}
return true;
}
};
So HNInfoIPComparator() would be generated depending on types passed as its arguments inside std::unique function.
Therefore I want to pass to std::unique templated functor (class). Is it possible to do that and how?
Also I want to handle case when functor contains some internal data, which are used for comparisons
Most important code samples:
// Automatically generated structure from IDL specification
// Basically simple structure
struct THNNetIPInfo
{
typedef THNNetIPInfo_var _var_type;
typedef THNNetIPInfo_out _out_type;
static void _tao_any_destructor (void *);
::TAO::String_Manager ipaddr;
::TAO::String_Manager netmask;
};
// THNNetIPInfoIter - class external iterator
// which was written manually
typedef Util::CorbaSeqIter<THNNetIPInfoList, THNNetIPInfo> THNNetIPInfoIter;
// THNNetIPInfoList - also automatically generated class
// from IDL specification, list of THNNetIPInfo elements
THNNetIPInfoList list(...);
THNNetIPInfoIter first(&list, 0);
THNNetIPInfoIter end(&list, list.length());

Instead of writing a class template with four comparison operators, write a plain class with a templated comparison operator that adapts the inputs into the keys you want to compare:
class HNInfoIPComparator {
static const char* adapt(const THNNetIPInfo& t) {
return t.ipaddr.in();
}
static const char* adapt(const SDK::TIPAddressDescription& t) {
return t.ip_address().c_str();
}
public:
template <typename T, typename U>
bool operator()(const T& t, const U& u) const {
return !strcmp(adapt(t), adapt(u));
}
};
You can extend the comparator easily by adding overloads of adapt for additional types, e.g., std::string or const char*.

Related

Comparator for sort, specialization

In a template function a std::vector shall get sorted. T can be a simple type or a std::pair e.g.,
std::vector<double> or
std::vector<std::pair<int,Something> >
When T is a pair then only the first element shall be compared. How can I implement the comparator for the two cases?
I have tried:
template<typename T>
inline bool smaller(const T& a,const T& b)
{
return a<b;
}
template<typename T,typename S>
inline bool smaller(
const std::pair<T,S>& a,
const std::pair<T,S>& b
)
{
return a.first<b.first;
}
template<typename T> inline void function(std::vector<T >& vVec)
{
...bla...
sort(vVec.begin(),vVec.end(),smaller<T>);
...bla...
}
but it does not work this way. I have also tried specialization but I do not find the right syntax to specialize the smaller() function.
You could just wrap it in a lambda:
std::sort(vVec.begin(),vVec.end(), [](const auto& a, const auto& b) { return smaller(a, b); });
One easy work around is to make both of your smaller functions opeator()'s of a smaller struct. Using
struct smaller
{
template<typename T>
bool operator()(const T& a,const T& b)
{
return a < b;
}
template<typename T, typename S>
bool operator() (const std::pair<T, S>& a, const std::pair<T, S>& b)
{
return a.first < b.first;
}
};
allows you to just pass a smaller to sort like
template<typename T> inline void function(std::vector<T >& vVec)
{
sort(vVec.begin(),vVec.end(),smaller{});
}
and in sort overload resolution will kick in on the two operator() smaller has and for any std::vector<std::pair>, the std::pair overload will be called.

Operator overloader not making an affect

I am attempting to create a class that takes a priority queue and reverses the priorities. I include a bool operator<() function as a member function of the class, but no matter how I structure this function, the operator never seems to be overloaded.
Here is my class:
template<typename T>
class MinPQ{
public:
bool empty() const {
return pq.empty();
}
unsigned int size() const {
return pq.size();
}
void push(const T& element){
pq.push(element);
}
const T& min() const {
return pq.top();
}
void remove_min(){
pq.pop();
}
bool operator<(const T& element) const {
return pq < element;
}
private:
priority_queue<T> pq;
};
EDIT
I also tried changing the overloading function to the following and do not undertsand why that isn't working either.
bool operator<(const T& element){
return this < element;
}
Your operator< is meaningless. The only thing it can do is comparing MinPQ<T> object with T object. If you want to compare two T objects you should do this:
1) If the template type T can take only a handful of types, you can write comparison operators explicitly for each of these types:
bool operator<(const T& lhs, const T& rhs)
{
return lhs > rhs;
}
note: each operator< should be a non-member function. Or a member function of class T with a single argument.
2) write a comparison functor:
template <class T> struct CompareT
{
bool operator()(const T& lhs, const T& rhs) const
{
return lhs > rhs;
}
};
and then declare pq member as follows:
priority_queue<T, std::vector<T>, CompareT<T>> mq;
3) If you want simply to inverse priorities, you could simply use std::greater class:
priority_queue<T, std::vector<T>, std::greater<T>> mq;

Defining hash function as part of a struct

I know that it's possible to define a hash function for a struct X by defining a separate hash function struct:
struct hash_X {
size_t operator()(const X &x) const {}
bool operator()(const X &a, const X &b) const {}
};
int main() {
unordered_set<X, hash_X, hash_X> s;
}
But I'm looking for something like operator<, which can be attached to struct X itself, e.g. with set:
struct X {
bool operator<(const X &other) const {}
};
int main() {
set<X> s;
}
The end goal is something like:
struct X {
size_t operator()(void) const {}
bool operator()(const X &other) const {}
};
int main() {
unordered_set<X> s;
}
Is this possible in C++?
std::unordered_set is defined within std namespace. And it uses std::hash structures to hash many different types. If you want to be able to use std::unordered_set<X> (without adding much info to the declaration), you must create another overload of the std::hash template, so as to make it hash your structure.
You should be able to get it working by doing the following:
# include <unordered_set>
struct X {
size_t operator()(void) const {}
bool operator()(const X &other) const {}
};
namespace std {
template<>
struct hash<X> {
inline size_t operator()(const X& x) const {
// size_t value = your hash computations over x
return value;
}
};
}
int main() {
std::unordered_set<X> s;
}
Andalso, you must provide either an overload to std::equal_to, or a comparison operator (operator==()) for your structure. You should add one of the following:
struct X {
...
inline bool operator==(const X& other) const {
// bool comparison = result of comparing 'this' to 'other'
return comparison;
}
};
Or:
template <>
struct equal_to<X> {
inline bool operator()(const X& a, const X& b) const {
// bool comparison = result of comparing 'a' to 'b'
return comparison;
}
};
There is no hash operator, but you could hide the hash struct inside of your X:
struct X
{
std::string name;
struct hash
{
auto operator()( const X& x ) const
{ return std::hash< std::string >()( x.name ); }
};
};
You could even make it a friend and make name private, etc.
Live example
namespace hashing {
template<class T>
std::size_t hash(T const&t)->
std::result_of_t<std::hash<T>(T const&)>
{
return std::hash<T>{}(t);
}
struch hasher {
template<class T>
std::size_t operator()(T const&t)const{
return hash(t);
}
};
}
the above is some boilerplate that sets up an adl-based hash system.
template<class T>
using un_set=std::unordered_set<T,hashing::hasher>;
template<class K, class V>
using un_map=std::unordered_map<K,V,hashing::hasher>;
now creates two container aliases where you do not have to specify the hasher.
To add a new hashable:
struct Foo {
std::string s;
friend size_t hash(Foo const&f){
return hashing::hasher{}(s);
}
};
and Foo works in un_set and un_map.
I would add support for std containers and tuples into hashing namespace (override the function hash for them), and magically those will work too.
I'd recommend to consider a more general hash class. You could define for this class all the common hash manipulation operations that you could need:
struct ghash {
// all the values and operations you need here
};
Then in any class where you want to compute a hash, you could define a conversion operator
struct X {
operator ghash () { // conversion operator
ghash rh;
// compute the hash
return rh;
}
};
You can then easily calculate the hash:
X x;
ghash hx = x; // convert x to a hash
hx = (ghash)x; // or if you prefer to make it visible
This will make it easier to extend the use of your hash structure without reinventing the common ground for any other struct X, Y,Z that may need a hash in the future.
Live demo here

implementing a generic binary function with a class and functor as template parameters

I am trying to wrap some templated functions into some binary functors like below. When I try to compile the code I have the error
error: no match for call to ‘(QtyAsc) (myobj&, myobj&)
I thought that being operator() in QtyAsc a function in a class, the template deduction mechanism would have worked but it seems that the compiler doesn't accept myobj classes as valid types for it.
Is it maybe because of the call to boost::bind? I was trying to provide a default implementation for the second templated argument (unfortunately I cannot use C++11 with default templated arguments).
class myobj {
public:
myobj(int val) : qty_(val) {}
int qty() { return qty_;}
private:
int qty_;
};
template<class T>
int get_quantity(const T& o) {
throw runtime_error("get_quantity<T> not implemented");
}
template<>
int get_quantity(const myobj& o) {
return o.qty();
}
struct QtyAsc {
template<class T, class QEx >
bool operator()(const T& o1, const T& o2, QEx extr = boost::bind(&get_quantity<T>,_1)) const {
if(extr(o1) < extr(o2))
return true;
return false;
}
};
int main() {
myobj t1(10),t2(20);
QtyAsc asc;
if(asc(t1,t2))
cout << "Yes" << endl;
}
If you can't use C++11, just provide an additional overload:
struct QtyAsc {
template<class T, class QEx >
bool operator()(const T& o1, const T& o2, QEx extr) const {
return extr(o1) < extr(o2);
}
template<class T>
bool operator()(const T& o1, const T& o2) const {
return operator()(o1, o2, &get_quantity<T>);
}
};
(I've omitted the unnecessary boost::bind.) Also, you will need to declare myobj::qty to be const:
int qty() const {
return qty_;
}
since you want to invoke it on const objects. (Live demo)

unordered_set storing elements as pointers

To narrow it down: I'm currently using Boost.Unordered. I see two possible solutions:
Define my own Equality Predicates and Hash Functions and to utilize templates (maybe is_pointer) to distinct between pointers and instances;
Simply to extend boost::hash by providing hash_value(Type* const& x) as for hashing; and add == operator overload as free function with (Type* const& x, Type* const& y) parameters as for equality checking.
I'm not sure whether both variations are actually possible, since I didn't test them. I would like to find out you handle this problem. Implementations are welcome :)
EDIT 1:
What about this?
template<class T>
struct Equals: std::binary_function<T, T, bool> {
bool operator()(T const& left, T const& right) const {
return left == right;
}
};
template<class T>
struct Equals<T*> : std::binary_function<T*, T*, bool> {
bool operator()(T* const& left, T* const& right) const {
return *left == *right;
}
};
EDIT 2:
I've just defined:
friend std::size_t hash_value(Base const& base) {
boost::hash<std::string> hash;
return hash(base.string_);
}
friend std::size_t hash_value(Base* const& base) {
return hash_value(*base);
}
And then:
Derived d1("x");
Derived d2("x");
unordered_set<Base*> set;
set.insert(&d1);
assert(set.find(&d2) == end());
Debugger says that friend std::size_t hash_value(Base* const& base) is never called (GCC 4.7). Why is that?
EDIT 3:
I found out that template <class T> std::size_t hash_value(T* const& v) in boost/functional/hash.hpp on line #215 (Boost 1.49) is Boost's specialization for pointers and it simply masks your custom implementation of hash_value such as mine in EDIT 2.
Therefore, it seems like the only way here is to create a custom Hash Functor.
For the hash function, you have a choice between specializing boost::hash (or std::hash in the newer standard) or defining a new functor class. These alternatives work equally well.
For the equality operator, you need to define a new functor, because you cannot redefine the equality operator over pointers. It's a built-in operator (defined in functional terms as bool operator==( T const *x, T const *y )) and cannot be replaced.
Both of these can be defined generically by using a templated operator() in a non-templated class.
struct indirect_equal {
template< typename X, typename Y >
bool operator() ( X const &lhs, Y const &rhs )
{ return * lhs == * rhs; }
};
Follow a similar pattern for the hasher.
Taking into consideration all edits in the original post I would like to provide complete solution which satisfies my needs:
1. Equality:
template<class T>
struct Equal: ::std::binary_function<T, T, bool> {
bool operator()(T const& left, T const& right) const {
::std::equal_to<T> equal;
return equal(left, right);
}
};
template<class T>
struct Equal<T*> : ::std::binary_function<T*, T*, bool> {
bool operator()(T* const & left, T* const & right) const {
Equal<T> equal;
return equal(*left, *right);
}
};
2. Hashing:
template<class T>
struct Hash: ::std::unary_function<T, ::std::size_t> {
::std::size_t operator()(T const & value) const {
::boost::hash<T> hash;
return hash(value);
}
};
template<class T>
struct Hash<T*> : ::std::unary_function<T*, ::std::size_t> {
::std::size_t operator()(T* const & value) const {
Hash<T> hash;
return hash(*value);
}
};
So now I can continue using Boost's hash_value and it will not get masked for pointer types by Boost's default implementation (see EDIT 3).
3. Example:
In my application I have a thin wrapper for unordered_set which now looks like that:
template<class T, class H = Hash<T>, class E = Equal<T> >
class Set {
public:
// code omitted...
bool contains(const T& element) const {
return s_.find(element) != end();
}
bool insert(const T& element) {
return s_.insert(element).second;
}
// code omitted...
private:
::boost::unordered::unordered_set<T, H, E> s_;
};
So if we have some base class:
class Base {
public:
Base(const ::std::string& string) {
if (string.empty())
throw ::std::invalid_argument("String is empty.");
string_ = string;
}
virtual ~Base() {
}
friend bool operator==(const Base& right, const Base& left) {
return typeid(right) == typeid(left) && right.string_ == left.string_;
}
friend bool operator!=(const Base& right, const Base& left) {
return !(right == left);
}
friend ::std::size_t hash_value(Base const& base) {
::boost::hash<std::string> hash;
return hash(base.string_);
}
friend ::std::size_t hash_value(Base* const& base) {
return hash_value(*base);
}
private:
::std::string string_;
};
And some derived class:
class Derived: public Base {
public:
Derived(const ::std::string& string) :
Base(string) {
}
virtual ~Derived() {
}
};
Then we can even use polymorphism (which was my primary intention BTW):
Derived d1("¯\_(ツ)_/¯");
Derived d2("¯\_(ツ)_/¯");
Set<Base*> set;
set.insert(&d1);
assert(set.contains(&d2));
Hope this helps. Any suggestions are welcome.