adding arrays of different types (c++) - 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;
}

Related

C++ functors, any effective aproach?

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

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.

How to promote two template types for arithmitic operations like builtin types do?

If I have a generic struct/class:
template<typename T>
struct Container
{
T value;
Container(const Value& value) : value(value) { }
};
And I want to perform an operation on two of them:
template<typename T, typename U>
Container<T> operator+(const Container<T>& lhs, const Container<U>& rhs)
{
return Container<T>(lhs.value + rhs.value);
}
The problem is that if lhs is of the type Container<int> and rhs is of the type Container<float>, then I'll get a Container<int> back. But if I were to do auto result = 2 + 2.0f, then result would of of type float. So the behavior is inconsistent between builtin types and custom types.
So how would I take the operator+ overload and make it return Container<float>, much like how C++ handles arithmetic promotion with builtin types?
As far as you use one of the two types of the template, you risk to induce a cast on the result of the sum. As an example, if you accidentally choose int as your target type, even though the sum results in a float, it will be cast down to the chosen type.
Anyway, starting with C++11, you con rely on the decltype specifier as in the example above (or at least, you can do that if Container::T and Container::U are a types for which the + operator is defined).
I used also the auto specifier as return value for the operator+, for it is at our disposal starting from C++14 and it's really useful indeed.
It follows the working example above mentioned:
#include <iostream>
#include <vector>
template<typename T>
struct Container
{
T value;
Container(const T& value) : value(value) { }
};
template<typename T, typename U>
auto operator+(const Container<T>& lhs, const Container<U>& rhs)
{
return Container<decltype(lhs.value+rhs.value)>{lhs.value + rhs.value};
}
int main()
{
Container<int> c1{1};
Container<float> c2{0.5};
std::cout << (c1+c2).value << std::endl;
}

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).

I need someone who explain me these lines of code

I need someone who explain me this code, line by line. I specially don't understand this line:
operator std::map<T, U>()
Thank you very much.
template <typename T, typename U>
class create_map
{
std::map<T, U> m_map;
public:
create_map(const T& key, const U& val)
{
m_map[key] = val;
}
create_map<T, U>& operator()(const T& key, const U& val)
{
m_map[key] = val;
return *this;
}
operator std::map<T, U>()
{
return m_map;
}
};
operator std::map<T, U>()
{
return m_map;
}
This is user-defined conversion function.
That means, you can write this:
//obj is an object of type create_map
create_map<int,std::string> obj(1,"Nawaz");
//obj implicitly converts into std::map type!
std::map<int,std::string> map_inst=obj;
See this topic to know more about user-defined conversion function:
User Defined Conversions in C++
You can see this as well: Implicit conversion sequences (C++ only)
create_map<T, U>& operator()(const T& key, const U& val)
{
m_map[key] = val;
return *this;
}
This actually overloads the operator(), which internally inserts or updates (key,val) pair into the m_map; just see the function definition as to what it does.
So using this function you can write code like this,
obj(2,"Sarfaraz"); //this inserts the pair into the underlying m_map;
I would also suggest you to explore std::map a bit more, especially the overloaded operator[] in std::map.
Code:
template <typename T, typename U>
class create_map
{
std::map<T, U> m_map;
public:
create_map(const T& key, const U& val)
{
m_map[key] = val;
}
create_map<T, U>& operator()(const T& key, const U& val)
{
m_map[key] = val;
return *this;
}
operator std::map<T, U>()
{
return m_map;
}
};
The purpose of this code is to be able to specify a map with specific key/value pairs, by chaining calls to operator(), like
create_map<int, std::string>( 1, "blah" )( 2, "hah" )( 3, "doh" )
Since the class does not have a default constructor, there's no way to use it to create an empty map. That may be by design. Or it may be a design error.
The
operator std::map<T, U>()
{
return m_map;
}
defines a conversion to std::map<T, U>, which is the end result of it all.
It can be invoked implicitly wherever a create_map is specified and a std::map is expected, such as using a create_map expression as argument in a function call.
However, it can be pretty inefficient since it copies the map. The compiler may well optimize away the copying. But it’s ungood to needlessly rely on Quality Of Implementation (although sometimes that is the best that one can do).
So it should instead be
operator std::map<T, U> const& () const
{
return m_map;
}
The const at the end there allows a create_map to be declared as const and used.
With this conversion to reference there is the same problem as with using reference arguments, namely a theoretical possibility of aliasing, where code that retains a reference to const is not prepared to deal with changes of the referred object. But in practice it’s not a problem. For example, as formal argument one just writes std::string const& s (instead of just std::string s) as a matter of course, and very few if any errors result from that – I’ve never experienced any problem.
Cheers & hth.,
There's not much to understand about it. operator std::map<T, U>() overrides the class' conversion operator (which takes no parameters) to provide an object instance of type std::map<T, U>. std::map is a STL standard class for associative key->value storage. In your case it maps from keys of type T to values of type U. T and U have been undefined so far (you wrote template class, but where are the template parameters?)
The conversion operator allows to use the class instance in place of the type the operator provides conversion for, like this.
class foo {
operator char const *() {
return "foo instance as char const *";
}
};
// ...
void bar(foo &f)
{
// here the class instance is used as if it were a char const *
cout << f << endl;
}
The line
operator std::map<T, U>()
defines a function that will be called when your create_map object is used like an std::map somewhere in the code.
An easier example would be:
class A
{
public:
operator int()
{
return 3;
}
};
int main()
{
A a;
cout << a << endl;
}
Now the computer finds out that it doesn't know how to print variable a, but it knows how to convert it to an int and then print it. So "3" gets printed.