C++ functors, any effective aproach? - c++

In my C++ code I wrote two functors that take to arguments one returns the sum and the other returns the subtract so I could use them as arguments to functions. like this:
template<class T>
class AddValues{
public:
T operator()(const T &value1, const T &value2) {
return value1 + value2;
}
};
template<class T>
class SubstractValues{
public:
T operator()(const T &value1, const T &value2) {
return value1 - value2;
}
};
But now I am looking to write like 6 functors that each one of them takes two arguments and returns true/false wither the first value is <,<=,>,>=,==,!= than the other.
Is there a clearer way to do that rather than defining 6 classes?
I'm working with C++11

Note: This post is a refinement of my comments to the original post.
First, you should be aware that the STL already defines a set of functors. See https://en.cppreference.com/w/cpp/header/functional under Comparators for <,<=,>,>=,==,!=, and Arithmetic operations for +,- (which you have redefined). It is good practice to know the STL and how to use it.
How to use them
Functors are objects like any other object and are to be used with value semantics. For a functional look, they define the function operator (operator()) and can be called () on the object directly.
std::less is_less;
bool is_0_less_than_0 = is_less(0,1); // Calls bool operator()(int, int) and evaluates to true
The functors are usually used in combination with the algorithms. For a not so pretty use case to compare two arrays of integers:
std::array<int,4> low_numbers = {1,2,3,4};
std::array<int,4> high_numbers = {5,6,7,8};
std::array<bool,4> is_number_greater;
// compares low_numbers and high_numbers element wise and stores result in is_number_greater.
std::transform(low_numbers.begin(),
low_numbers_low.end(),
high_numbers.begin(),
is_number_greater.begin(),
std::greater{});
How to write your own functors
So you have already (functionality wise) redefined std::plus (as AddValues) and std::minus (as SubtractValues). Note that I say functionality wise, since it is more flexible to only templatize the function operator:
struct AddValues{
template<class T>
T operator()(const T &value1, const T &value2) {
return value1 + value2;
}
};
And as the member method operator() does not modify any members of AddValues, it should be marked const:
struct AddValues{
template<class T>
T operator()(const T &value1, const T &value2) const {
return value1 + value2;
}
};
Then you do not need to specify the type when instantiating the object. Compare template class:
AddValues<int> add_values; // templated type has to be explicitly written.
add_values(1,2); //=3
with templated method:
AddValues add_values;
add_values(1,2); //=3, types deduced when calling method.
.
Anyway, you would have to do the same for <,<=,>,>=,==,!=, since you need a wrapper around each operator. The difference would only be that now you return booleans instead of a type.
struct MyLess
{
template<typename T>
bool operator()(const T& lhs, const T& rhs) const { return lhs < rhs; }
};

Related

Hashable type with overwritten operators or external functors

To use a custom type in a std::unordered_set I have to options.
1) Implement the == operator for my type and specialize std::hash
struct MyType {
int x;
bool operator==(const MyType& o) {
return this.x == o.x;
}
};
namespace std
{
template<>
struct hash<MyType> {
size_t operator()(const MyType& o) const {
return hash<int>()(o.x);
}
};
}
std::unordered_set<MyType> mySet;
Or 2), provide functor classes:
struct MyTypeHash {
size_t operator()(const MyType& o) const {
return std::hash<int>()(o.x);
}
};
struct MyTypeCompare {
bool operator()(const MyType& o1, const MyType& o2) const {
return o1.x == o2.x;
}
};
std::unordered_set<MyType, MyTypeHash, MyTypeCompare> mySet;
The second approach lets me choose new behaviour for every new instantion of std::unordered_set, while with the first approach the behaviour as being part of the type itself will always be the same.
Now, if I know that I only ever want a single behaviour (I'll never define two different comparators for MyType), which approach is to be preferred? What other differences exist between those two?
Attaching the behavior to the type allows for code like
template<template<class> Set,class T>
auto organizeWithSet(…);
/* elsewhere */ {
organizeWithSet<std::unordered_set,MyType>(…);
organizeWithSet<std::set,MyType>(…);
}
which obviously cannot pass custom function objects.
That said, it is possible to define
template<class T>
using MyUnorderedSet=std::unordered_set<T, MyTypeHash,MyTypeCompare>;
and use that as a template template argument, although that introduces yet another name and might be considered less readable.
Otherwise, you have to consider that your operator== is simultaneously the default for std::unordered_set and std::find, among others; if the equivalence you want for these purposes varies, you probably want named comparators. On the other hand, if one suffices, C++20 might even let you define it merely with =default.

Modify std::less on a shared_ptr

This is what I have:
struct Foo {
int index;
}
std::set<std::shared_ptr<Foo>> bar;
I want to order bar's elements by their indices instead of by the default std::less<std::shared_ptr<T>> function, which relates the pointers.
I read I can type std::set<std::shared_ptr<Foo>, std::owner_less<std::shared_ptr<Foo>>> bar, but I'd prefer to stick to the previous syntax.
I tried defining std::less<std::shared_ptr<Foo>>, but it's not actually being used by the set functions. Is there a way I can achieve this?
If you want to compare by their indices, you'll have to write a comparator that checks by their indices. std::less<> will do the wrong thing (since it won't know about index) and std::owner_less<> will do the wrong thing (since it still won't compare the Foos, but rather has to do with ownership semantics of them).
You have to write:
struct SharedFooComparator {
bool operator()(const std::shared_ptr<Foo>& lhs,
const std::shared_ptr<Foo>& rhs) const
{
return lhs->index < rhs->index;
}
};
and use it:
std::set<std::shared_ptr<Foo>, SharedFooComparator> bar;
You could additionally generalize this to a generic comparator for shared_ptr's:
struct SharedComparator {
template <typename T>
bool operator()(const std::shared_ptr<T>& lhs,
const std::shared_ptr<T>& rhs) const
{
return (*lhs) < (*rhs);
}
};
and then simply make Foo comparable.
You can provide your own specialization of less<shared_ptr<Foo>> in the std namespace.
namespace std
{
template<>
class less<shared_ptr<Foo>>
{
public:
bool operator()(const shared_ptr<Event>& a, const shared_ptr<Event>& b)
{
// Compare *a and *b in some way
}
};
}
Then you can form a set<shared_ptr<Foo>> without a comparator. I needed this for a priority_queue<shared_ptr<Foo>>, where I didn't want to use a priority_queue<Foo*, vector<Foo*>, int (*)(const Foo*, const Foo*)>. I am not proud of it, but it works.

Comparing struct in c++

Do anyone know a general method to declare a comparision function for struct so that I can use it in sort , priority queue , map ,set ...
I would also know how to specify the comparision function when declaring a data structure (like map ) having a structure as a key (in the case where i have two or more comparision functions)
Thank you in advance
How can the method be "general"?
Let's say you have this struct.
struct MyStruct{
A a; // A is your own class
};
How would the compiler know how to compare objects of type A?
You need to define a comparison operator yourself.
bool operator()(const MyStruct& s1, const MyStruct& s2);
This function can be given as a compare-function when creating for example a std::map.
explicit map (const key_compare& comp = key_compare(),
const allocator_type& alloc = allocator_type());
std::map
comp: Binary predicate that, taking two element keys as argument, returns true if the first argument goes before the second argument in the strict weak ordering it defines, and false otherwise.
defaults to
less<key_type>
The comparison function depends from the semantics of your struct. What does it mean that a < b for your type?
In general, a compare function is something along the line of this (references are optional):
bool comp( const YourType& a, const YourType& b );
To make a map use your compare function, you must write like this:
#include <map>
struct YourType{
int v;
};
struct YourTypeComparison{
bool operator()( const YourType& a, const YourType& b ) { return a.v < b.v; }
};
int main()
{
std::map<YourType,int, YourTypeComparison> m;
}
Normally you would use the standard containers like std::map< std::string, int >. But they also have a Comparator type and an Allocator type.
The Comparator used by default is std::less, which looks somewhat like this,
template <class T>
struct less : binary_function <T,T,bool> {
bool operator() (const T& x, const T& y) const {
return x<y;
}
};
(There are some other already made functors http://en.cppreference.com/w/cpp/utility/functional)
Notice that it compares two objects with <. This means that as a "general method" you only need to implement the operator bool operator< (const X& lhs, const X& rhs){...} to allow your objects to be sorted. See Operator Overloading FAQ. As a rule of thumb, if you're going to implement one comparison operator then you should implement the others too.
If you need to sort your keys in another way you can define your own comparator (functor).
template < class T >
struct myLess {
bool operator()( const T& lhs, const T& rhs ) const {
return lhs < rhs;
}
};
And use it in a map like std::map< int, int, myLess<int> >.
You can also not use templates at all if you only need to compare one type.
struct myLess {
bool operator()( const int& lhs, const int& rhs ) const {
return lhs < rhs;
}
};
Then you only have to write std::map< int, int, myLess >.
Keep in mind that the objects you're comparing are the Key types, not necessarily the Contained types.

adding arrays of different types (c++)

i need to dynamically create arrays containing different numerical types, including char, int, unsigned int, float, double. i'd like to be able to create any two of these arrays and, assuming they're of the same length, implement arithmetic operators such as operator+=
i've been able to implement the array as a template, but i don't know how to implement any arithmetic operators, since i can't know what the other array's type will be at compile time, or even when the first array is created (i will know the type for the array i'm constructing). i looked at std::array, but it doesn't support arithmetic operators. another alternative, which is definitely not elegant (but does work), is to implement a series of type specific operators, such as
MyArray<V> operator+ (const MyArray<float>& addend) const;
MyArray<V> operator+ (const MyArray<double>& addend) const;
MyArray<V> operator+ (const MyArray<int32>& addend) const;
MyArray<V> operator+ (const MyArray<int16>& addend) const;
thanks for any advice.
Alright, its probably obvious enough from my comments of everything in this thread that this is a particular sore spot for me. And this is for good reason, I was once like you. I was like, I can overload operators! AMAZING! OVERLOAD ALL THE OPERATORS (this was with a custom image container type). After a while, a few things became clear:
Operators are hard to correctly declare, especially templated ones.
Templated operators cannot have their types set explicitely, only implicitly.
Operation order doesn't make sense all the time.
Operators must either use exceptions as their "fail" mode which is not ideal in all cases, or use "enable-if" type syntax if the fail can be detected at compile time.
Operator MEANING is hard to document/elucidate. Different interpretations of what an operator should "do" makes it hard to figure out. (Should the MyArray<T>+MyArray<J> work as a memberwise plus like T+J or should it work like a concatenate like 'string+string'?)
Operators must return by value, which can cause overhead if your moves aren't all set up correctly/you aren't in C++11/for any reason return value elision doesn't happen.
Overall, writing your own container types is a great way to redo alot of work the STL has already done.
You COULD do it like (at a namespace scope) (assuming you have a templated cast operator available)
template <typename T, typename J>
MyArray<decltype(T()+J())> operator+(const MyArray<T>& x,const MyArray<J>& y)
{
using K=decltype(T()+J());
MyArray<K> ret(x.size());//or something?
for (size_t i = 0; i < x.size(); i++) {ret[i]=x[i]+y[i];}//could replace with foreach
return ret;
};
Though using the following with vectors just makes more sense. You can wrap it in a "add" call if you want.
std::vector<T> a;//or whatever
std::vector<J> b;//or whatever
std::vector<K> c(a.size());//note: you can still use the decl type here, OR just define it to whatever you actually want it to be
std::transform(a.begin(), a.end(). b.begin(), c.begin(), std::plus<K>());
If you are trying to do this all over the place, and are trying to make a matrix math library, use one like Eigen, it'll save you a lot of work, it'll be strongly typed as a matrix and not a generic collection, and it'll be done with the full math knowledge the Eigen team has.
You can use one more template parameter:
template<class V, class T> MyArray<V> operator+ (const MyArray<T>& addend) const;
Then the cast will always be according to your main array type.
You will likely have to dispatch your operations by a result type selected by some type traits.
Simplified for a number (no vector):
#include <iostream>
template <typename T>
struct Number {
T value;
Number(T value) : value(value) {}
template <typename U>
explicit Number(U value) : value(value) {}
operator T () const { return value; }
};
#define C_PLUS_PLUS_11 (201103L <= __cplusplus)
template <typename U, typename V>
struct binary_operation_traits {
#if C_PLUS_PLUS_11
typedef decltype(U() + V()) result_type;
#endif
};
#if ! C_PLUS_PLUS_11
template <typename T>
struct binary_operation_traits<T, T> {
typedef T result_type;
};
template <>
struct binary_operation_traits<int, float> {
typedef float result_type;
};
template <>
struct binary_operation_traits<int, double> {
typedef double result_type;
};
// And so on ...
#endif
template <typename U, typename V>
Number<typename binary_operation_traits<U, V>::result_type>
operator + (const Number<U>& a, const Number<V>& b) {
typedef typename binary_operation_traits<U, V>::result_type result_type;
return Number<result_type>(result_type(a) + result_type(b));
}
int main ()
{
Number<int> a(1);
Number<double> b(1.5);
std::cout << a + b << '\n';
return 0;
}

c++ - Priority Queue - How does it work internally?

Say I have this declaration of a priority queue:
struct orderByRewards{
bool operator() (pair<int,pair<int,int> > a, pair<int, pair<int, int> > b){
return a.first < b.first;
}
};
priority_queue<pair<int,pair<int,int> >, vector<pair<int,pair<int,int> > >, orderByRewards> Q;
I was wondering if anybody could take their time and explain me how does the compiler interpret the compare class.
Why do I need to overload the () operator ?
Also, where's the () operator used in its comparing process ?
It feels a little weird, especially since I am not really comfortable with templates and all OOP concepts.
Why do we need to declare the type of a single object and the container type ?
You're essentially asking about function objects (or functors). A function object is one that overloads operator(). You can use such an object as though it were a function. The standard provides a few comparison functors (like your orderByRewards). For example, std::less looks something like this:
template <class T>
struct less {
constexpr bool operator()(const T &lhs, const T &rhs) const
{
return lhs < rhs;
}
};
As we can see, the overloaded operator() just compares the two arguments using < and then returns the boolean result. To use this, you need to create an object of type std::less and then use the function call syntax on it:
std::less<int> compare;
assert(compare(5, 7) == true);
Even though compare is an object, we were able to use it like a function in compare(5, 7).
So now we know that your type orderByRewards is a function object type. You are passing it as a template type argument of std::priority_queue. The implementation of std::priority_queue can then create objects of this comparison function object when it needs to compare elements within the queue.
Consider a simpler example:
template <typename T, typename Comp>
struct foo {
void bar(T a, T b) {
Comp compare;
if (compare(a, b)) {
std::cout << "True" << std::endl;
} else {
std::cout << "False" << std::endl;
}
}
};
It's a silly example, but it gets the point across. We can use this like so:
foo<int, std::less<int>> my_foo;
my_foo.bar(5, 7); // Will print true
We were able to configure foo, by passing it some arbitrary comparison functor type, that its member function bar was able to instantiate and use.
So in the same way, you are configuration std::priority_queue by giving it a comparison functor type that it can use to order elements within the queue. This is how it determines priority between elements. In fact, the default template type argument for std::priority_queue is std::less.
You are not required to overfload the operator(). You can declare your custom method:
typedef bool (*comp)(int,int);
bool compare(int a, int b)
{
return (a<b);
}
int main()
{
std::priority_queue<int,std::vector<int>, comp> pq(compare);
return 0;
}
Updated:
As #WhozCraig pointed out:
It is possible to use this object without overloading the operator() but the compiler will face an easier situation inlining operator() comparison function rather than runtime-provided dereferenced comparison function
Perhaps it would make the most sense to look at the definition of std::priority_queue and work from there.
template <class T, class Container = vector<T>,
class Compare = less<typename Container::value_type> >
class priority_queue {
This says that Compare is some type, and defaults to std::less<T>, for T = the value_type of the underlying container. This compensates for the possibility that you might do something slightly insane like creating a priority_queue of one type, but have the underlying container hold another type (though that's not particularly likely, except by accident).
std::less, in turn, is defined like this:
template <class T> struct less {
bool operator()(const T& x, const T& y) const;
// plus a few typedefs for the argument and return types.
};
In short, it's a type defined with only one publicly available operation: an operator() that can be passed two items that it compares, and returns a bool to indicate whether the first is less than the second.
Since that's what std::priority_queue expects to use, whatever you provide must support essentially the same function call-like syntax and semantics (e.g., the operator() should take const arguments and should itself be const-qualified).