Function template with operator overloading - c++

I am learning templates and came across function templates.I have developed the following code out of my creativity or just curiosity.
#include<iostream>
using namespace std;
template <typename type>
type Max(type a, type b)
{
return a > b ? a : b;
}
class Foo
{
public:
string s1;
/*
Foo& operator>(Foo &obj)
{
if (this->s1.length() > obj.s1.length() ? true : false)
return *this;
return obj;
}*/
};
int main()
{
cout << Max(2, 3) << endl;
cout << Max(2.0, 3.0) << endl;
Foo a, b;
a.s1 = "AB";
b.s1 = "ABC";
//cout<<Max(a, b).s1;
}
My idea is to pass Foo objects a and b using the Max function template and overload the '>' operator and print the object's string with greater length.
Am i on the right path?Or should it be related to class templates?

You're on the right path, except that the > operator should take a const reference parameter, itself be a const class method, and return a bool:
bool operator>(const Foo &obj) const;
After all, what do you expect the result of > to be, with anything else, for example:
double a, b;
// ...
auto whatisthis= a > b;
Do you expect whatisthis to be a double? Of course not, it will be a bool. The result of any comparison operator, not only > should be a bool. It doesn't really have to be, you can overload the > operator and have it return anything; but that means that you couldn't use the way you expect to use it.

Let operator> return bool, otherwise it can't work with return a > b ? a : b;.
bool operator>(const Foo &obj)
{
return this->s1.length() > obj.s1.length();
}
BTW1: if (this->s1.length() > obj.s1.length() ? true : false) is redundant.
BTW2: It's better to make the parameter type to const since obj won't and needn't be modified.

The answer to your question is "Yes, you're on the right track."
The problem with generic functions is using them efficiently. Your Max() function works, but it copies Objects all over the place.
template <typename type>
const type &Max(const type &a, const type &b)
{
return a > b ? a : b;
}
This solves the Object copying problem - but now it's less efficient for things like ints.

#include <iostream>
using namespace std;
template <typename type>
type Max(type a, type b)
{
return a > b ? a : b;
}
class Foo {
public:
string s1;
bool operator > (Foo &obj) {
return this->s1.length() > obj.s1.length();
}
};
int main()
{
cout << Max(2, 3) << endl;
cout << Max(2.0, 3.0) << endl;
Foo a, b;
a.s1 = "AB";
b.s1 = "ABC";
cout << Max(a, b).s1;
}
This maybe what you want:

Related

C++ Templates for classes

in this code I tried to make a template for my class, and also 2 template functions, one for standard types and one for my template class, but I wanted to see if I can make a template in a template to get a defined function (I don't know if this was the right way to make it). Finally, after I run the code it gives me some weird errors, like syntax errors etc. Thx for help!
#include <iostream>
template <typename T>
class Complex
{
T _re, _im;
public:
Complex(T re = 0, T im = 0) :_re{re}, _im{im} {};
~Complex() {}
Complex<T>& operator=(const Complex<T>& compl) { if (this == &compl) return *this; this._re = compl._re; this._im = compl._im; return *this; }
Complex<T> operator+(const Complex<T>& compl) { Complex<T> temp; temp._re = _re + compl._re; temp._im = _im + compl._im; return temp}
friend std::ostream& operator<<(std::ostream& os, const Complex<T>& compl) { os << compl._re << " * i " << compl._im; return os; }
};
template <typename T>
T suma(T a, T b)
{
return a + b;
}
template <template<typename> typename T, typename U>
void suma(T<U> a, T<U> b)
{
T<U> temp;
temp = a + b;
std::cout << temp;
}
int main()
{
int a1{ 1 }, b1{ 3 };
std::cout << "Suma de int : " << suma<int>(a1, b1) << std::endl;
double a2{ 2.1 }, b2{ 5.9 };
std::cout << "Suma de double: " << suma<double>(a2, b2) << std::endl;
Complex<int> c1(3, 5), c2(8, 9);
std::cout << "Suma comple int: ";
suma<Complex, int>(c1, c2);
return 0;
}
compl is a c++ keyword (as an alternative for unary operator ~). You used compl as your operator overload parameters.
I didn't know this just a few minutes ago. How did I find out? I pasted your code into godbolt.org and it highlighted the words "compl" as if they were keywords. One Internet search later, they are indeed keywords.
There's also the use of this._re = ... and this._im = ... which doesn't work since this is a pointer and not a reference, so it should be this->_re = ... or preferably, just _re = ....
Your have 3 errors in your program.
First instead of using the keyword compl you could use some other name like i did here.
Second, you were missing a ; after a statement return temp which is fixed in the above code link.
Third you were using
this._re = rhs._re;
this._im = rhs._im;
while the correct way to write this would be:
_re = rhs._re;//note the removed this.
_im = rhs._im;//note the removed this.
After correcting these errors the program works as can be seen here.

STL and std custom compare arguments working in c++

I asked this question on stackoverflow STL passing object
I got to know that we pass objects which in tern call the compare operator in them and compare our values and gives us a result. All good.
Now in this piece of code:
class Compare {
public:
bool operator ()(const int &a, const int &b) { return a < b;}
};
void solve(){
set<int, Compare> s;
vector<int> arr = {1,4,6,3,7,2,8,588,5};
for(int e : arr) s.insert(e);
for(auto it = s.rbegin();it!=s.rend();it++) cout << *it << ' '; cout << endl;
}
I get error if I do Compare() which is what I thought must be done(passing an object). Why so? How can we pass Compare?
Also in this piece of code I cannot pass a function like:
bool comp(const int &a, const int &b) { return a < b; }
void solve(){
set<int, comp> s;
vector<int> arr = {1,4,6,3,7,2,8,588,5};
for(int e : arr) s.insert(e);
for(auto it = s.rbegin();it!=s.rend();it++) cout << *it << ' '; cout << endl;
}
Which is what I expect. Not passing functions.
Now in this piece of code:
bool comp(const int &a, const int &b) { return a < b; }
void solve(){
vector<int> arr = {1,4,6,3,7,2,8,588,5};
nth_element(arr.begin(), arr.begin()+3, arr.end(), comp);
for(int e : arr) cout << e << " "; cout << endl;
}
I am able to pass a function and there is no error. I mean what is going on? From my perspective, we should just pass objects and they will call their () overloaded operator and compare values but sometimes we are passing functions, sometimes passing objects giving error and sometimes we just pass class name. What is exactly going on in c++
Second template parameter of std::set is a type.
You might use function pointer:
bool comp(const int &a, const int &b) { return a < b; }
std::set<int, bool (*)(const int &, const int &)> s(comp);
In the first code snippet the compiler issues an error because you was using an object Compare() as the type template argument instead of the type Compare.
If you will write for example
#include <iostream>
#include <vector>
#include <set>
using namespace std;
class Compare {
public:
bool operator ()(const int &a, const int &b) const { return a < b;}
};
int main()
{
set<int, Compare> s( ( Compare() ) );
vector<int> arr = {1,4,6,3,7,2,8,588,5};
for(int e : arr) s.insert(e);
for(auto it = s.rbegin();it!=s.rend();it++) cout << *it << ' '; cout << endl;
return 0;
}
then the program compiles successfully and its output is
588 8 7 6 5 4 3 2 1
That is as the second type template argument of the class template std::set you need to use the type specifier Compare. But if you want to specify the argument of the constructor you need to use an object of the type of the template argument.
The same problem exists for the second code snippet. You need to write like it is shown in this demonstrative program.
#include <iostream>
#include <vector>
#include <set>
using namespace std;
bool comp(const int &a, const int &b) { return a < b; }
int main()
{
set<int, bool ( * )( const int &, const int & )> s( comp );
vector<int> arr = {1,4,6,3,7,2,8,588,5};
for(int e : arr) s.insert(e);
for(auto it = s.rbegin();it!=s.rend();it++) cout << *it << ' '; cout << endl; return 0;
}
The program output is the same as shown above.
Pay attention to that the class template std::set is declared like
template <class Key, class Compare = less<Key>,
class Allocator = allocator<Key> >
class set;
So if you specified explicitly the second template argument (instead of using by default the function object std::less<Key>) then you need to provide a corresponding object of this type in a constructor of the class template std::set.
operator() must be const. That's the API.
class Compare {
public:
bool operator ()(const int &a, const int &b) const { return a < b; }
}

How to compare two objects using templates?

I want to compare two objects and get larger among them using templates. Passing the object as an argument isn't working as the code below. See the sample code given below. That's what I'm trying to do.
#include <iostream>
using namespace std;
template <class T>
class max
{
T a;
public:
max(T a)
{
this.a = a;
}
T Large(T n2)
{
return (a > n2.a) ? a : n2.a;
}
};
int main()
{
max <int> obj1(10);
max <int> obj2(20);
cout<<obj1.Large(obj2)<<" is larger"<<endl;
return 0;
}
I'm doing something like this but by comparing 2 objects.
// class templates
#include <iostream>
using namespace std;
template <class T>
class mypair {
T a, b;
public:
mypair (T first, T second)
{a=first; b=second;}
T getmax ();
};
template <class T>
T mypair<T>::getmax ()
{
T retval;
retval = a>b? a : b;
return retval;
}
int main () {
mypair <int> myobject (100, 75);
cout << myobject.getmax();
return 0;
}
This code seems to work fine, let me know if this helps
#include <iostream>
using namespace std;
template <class T>
class Maxi {
T a;
public:
Maxi(T val)
{
this->a = val;
}
T Large(maxi n2)
{
return (a > n2.a) ? a : n2.a;
}
};
int main() {
Maxi <int> obj_1(10);
Maxi <int> obj_2(20);
cout<<obj_1.Large(obj_2)<<" is larger"<<endl;
return 0;
}
There is already a max and min template function provided under algorithm.
Just call std::max(10, 20) to get the larger between the two.
You can even provide your own comparator for custom comparison.
Side note: It seems like by including iostream, you can use max and min without algorithm.
Problems I see:
Use of
using namespace std;
is probably going to mess things up for you since std::max gets pulled into the mix indirectly. It does for me with g++. Don't use it.
Syntax error in the following line:
this.a = a;
That needs to be
this->a = a;
Argument to Large needs to be of type max, not T.
For good measure, I would also make it a const member function.
T Large(max n2) const
{
return (a > n2.a) ? a : n2.a;
}
Use std::cout and std::endl since using namespace std; is problematic.
Here's an updated version of your code with the above fixes:
#include <iostream>
template <class T>
class max
{
private:
T a;
public:
max(T a)
{
this->a = a;
}
T Large(max n2) const
{
return (a > n2.a) ? a : n2.a;
}
};
int main()
{
max <int> obj1(10);
max <int> obj2(20);
std::cout << obj1.Large(obj2) << " is larger"<<std::endl;
return 0;
}
It works for me and produces the following output:
20 is larger
I think you're trying to do this:
template <typename T>
T max(const T &a, const T &b)
{ return (b < a) ? a : b; }
That's how you do that. Your weird mishmash of a class doesn't make any sense at all. And so if I got what you're trying to do wrong, please explain yourself better.
Templates don't have to be classes you know. You can have templated functions.
If you absolutely must use a class, do this then:
template <typename T>
class max
{
T operator ()(const T &a, const T &b) { return (b < a) ? a : b; }
};
int main()
{
max<int> foo;
cout << foo(10, 20) << " is larger\n"; // Don't use endl most of the time.
return 0;
}
Suppose you have two objects that aren't ints, what do you do? Well, you do this:
#include <iostream>
#include <algorithm>
struct A {
int v1;
int v2;
};
bool operator <(A &a, A &b)
{
return (a.v1 < b.v1) || ((a.v1 == b.v1) && (a.v2 < b.v2));
}
::std::ostream &operator <<(::std::ostream &os, const A &a)
{
os << "{" << a.v1 << ", " << a.v2 << "}";
}
int main()
{
A first{10, 20};
B second{20, 10};
::std::cout << ::std::max(first, second) << " is the larger.\n";
}
If you don't want to have to define operator <, then do this:
bool my_less_than(const A &a, const A &b)
{
return (a.v1 < b.v1) || ((a.v1 == b.v1) && (a.v2 < b.v2));
}
int main()
{
A first{10, 20};
B second{20, 10};
::std::cout << ::std::max(first, second, my_less_than) << " is the larger.\n";
}

Explicit Instantiation of Templated Overloaded Operator

The following code works:
struct A
{
int v = 3;
};
namespace Foo
{
template <int k=11>
int operator+(A const& lhs, A const& rhs)
{
return lhs.v + rhs.v + k;
}
}
using Foo::operator+;
int main()
{
A a1, a2;
std::cout << a1 + a2 << std::endl;
return 0;
}
The using Foo::operator+; directive brings Foo::operator+ into the external lookup scope and the when operator+ is used in the cout call, the default template value of 11 is taken and the result is, as expected: 17 (=3+3+11).
My question is how to change the using clause to explicitly instantiate the operator+ function with a non-default template value?
The line using Foo::operator+<42> does not work.
This is due to ISO C++ Standard 7.3.3.5: A using-declaration shall not name a template-id.
Is there a way around this?
Answering myself...
The problem seems to stem from ISO C++ Standard 7.3.3.5:
A using-declaration shall not name a template-id.
This prevents the acceptance of: using Foo::operator+<42>.
As a work-around I found the following solution that does what I need, at the cost of an extra namespace redirection. The code may still need some massaging but it does get the task done with minimal duplication on the user's side.
See a working version here.
struct A
{
int v = 0;
};
template <int k>
struct Bar
{
static int plus(A const& lhs, A const& rhs)
{
return rhs.v + lhs.v + k;
}
};
namespace Boo
{
using Baz = Bar<42>; // same as `typedef Bar<42> Baz;`
//#include "foo_operators.h"
namespace Foo
{
int operator+(A const& rhs, A const& lhs)
{
return Baz::plus(lhs, rhs);
}
}
}
namespace Goo
{
using Baz = Bar<3>;
//#include "foo_operators.h"
namespace Foo
{
int operator+(A const& rhs, A const& lhs)
{
return Baz::plus(lhs, rhs);
}
}
}
using namespace std;
int main()
{
{
using Boo::Foo::operator+;
A a1, a2;
cout << a1 + a2 << endl;
}
{
using Goo::Foo::operator+;
A a1, a2;
cout << a1 + a2 << endl;
}
return EXIT_SUCCESS;
}
// In real code extract to foo_operators.h: the partial file snippets to get #included multiple times
// namespace Foo
// {
// int operator+(A const& rhs, A const& lhs)
// {
// return Baz::plus(lhs, rhs);
// }
// }
The idea is to replace the Foo namespace with a struct template with static methods Bar.
This allows instantiating the Foo type using the desired params.
The operators just call the static methods via the externally defined and parametrized type.
ADL takes care of the rest.
In the example above, the user created 2 new namespaces, Boo and Goo to have 2 different parametrizations of the plus operator. Finally, at the point of usage the user brings in the desired version of the operator+ with the using directive.
In this approach there doesn't seem to be an option for specifying default parameter values.
In real code the operators themselves would be stored in a snippet file to be #includeed into the code after the declaration of the parameterized type (Baz in the example).
Take 2
Here's a much cleaner version that uses a simple templated traits class and avoid both the extra namespace and the operator redirection function plus.
template <int k>
struct op_traits_t
{
static const int K = k;
};
namespace Boo
{
using op_traits = op_traits_t<42>; // same as `typedef op_traits_t<42> op_traits;`
//#include "foo_operators.h"
// this is a partial file snippet
int operator+(A const& rhs, A const& lhs)
{
return rhs.v + lhs.v + op_traits::K;
}
}
namespace Goo
{
using op_traits = op_traits_t<3>;
//#include "foo_operators.h"
// this is a partial file snippet
int operator+(A const& rhs, A const& lhs)
{
return rhs.v + lhs.v + op_traits::K;
}
}
int main()
{
{
using Boo::operator+;
A a1, a2;
cout << a1 + a2 << endl;
}
{
using namespace Goo;
A a1, a2;
cout << a1 + a2 << endl;
}
return EXIT_SUCCESS;
}
std::cout << operator+<12>(a1, a2) << std::endl;
But don't do this. Operator + should behave in an unsurprising way.
Use a named function:
namespace Foo
{
template <int k=11>
int add_plus_k(A const& lhs, A const& rhs)
{
return lhs.v + rhs.v + k;
}
}

Overload Function call operator () for find_if

I have three classes
class A
class B
class C
I have two maps
std::map<A*, B*> myMap1;
std::map<A*, C*> myMap2;
and object pointers of A
A* obj_ptr_A1 = new A; and so on
I want to perform a find_if on both the maps for A*, so I wrote a functor and overloaded operator () twice as follows
class functor
{
private:
A* m_member;
public:
explicit functor(A* input) : m_member(input){}
bool operator()(const std::pair<A*, B*>& iter) const
{
return (m_member->GetValue() == (iter.first)->GetValue());
}
bool operator()(const std::pair<A*, C*>& iter) const
{
return (m_member->GetValue() == (iter.first)->GetValue());
}
};
where GetValue() is a member function of A returning an integer.
Usage:
if(std::find_if(myMap1.begin(), myMap1.end(), functor(obj_ptr_A1)) != myMap1.end())
{
std::cout << "Found in myMap1" << std::endl;
}
if(std::find_if(myMap2.begin(), myMap2.end(), functor(obj_ptr_A1)) != myMap2.end())
{
std::cout << "Found in myMap2" << std::endl;
}
This gives me compilation error
error C3066: there are multiple ways that an object of this type can be called with these arguments
Is this overloading wrong?
Full code is here http://pastebin.com/DnUQKHPp It gives compilation error.
Try the following (Without testing)
template <class T>
class functor
{
private:
A* m_member;
public:
explicit functor(A* input) : m_member(input){}
bool operator()(const std::pair<A*, T*>& iter) const
{
return (m_member->GetValue() == (iter.first)->GetValue());
}
};
if(std::find_if(myMap1.begin(), myMap1.end(), functor<B>(obj_ptr_A1)) != myMap1.end())
{
std::cout << "Found in myMap1" << std::endl;
}
if(std::find_if(myMap2.begin(), myMap2.end(), functor<C>(obj_ptr_A1)) != myMap2.end())
{
std::cout << "Found in myMap2" << std::endl;
}
What I found is that if you make the comparison Argument a template parameter instead of A* you can do different key-value combinations in the map, provided you make the functor::operator() a template for the Iterator.
This is how the functor looks like:
template<typename Argument>
class functor
{
private:
Argument m_member;
public:
functor(Argument a)
:
m_member(a)
{}
template<typename PairIterator>
bool operator()(PairIterator iter) const
{
return (m_member->GetValue() == (iter.first)->GetValue());
}
};
This is the functor generator:
template<typename Argument>
functor<Argument> make_functor(Argument const & a)
{
return functor<Argument>(a);
}
and here is the complete online example.