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";
}
Related
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; }
}
I got to know that we can also pass template arguments to choose which function should execute. I found them good alternative to function pointers since function pointers has run time cost but template parameters does not. Also, template parameters can be made inline whereas function pointers are not.
Alright then, this is what I wrote to depict my understanding on it. I came close but missing some minor detail somewhere.
template<class T>
class String {
public:
T str;
String() { std::cout << "Ctor called" << std::endl; }
};
template<class T, class C>
int compare(const String<T> &str1,
const String<T> &str2) {
for (int i = 0; (i < str1.length()) && (i < str2.length()); ++i) {
if (C::eq(str1[i], str2[i])) {
return false;
}
}
return true;
}
template<class T>
class Cmp1 {
static int eq(T a, T b) { std::cout << "Cmp1 called" << std::endl; return a==b; }
};
template<class T>
class Cmp2 {
static int eq(T a, T b) { std::cout << "Cmp2 called" << std::endl; return a!=b; }
};
int main() {
String<std::string> s;
s.str = "Foo";
String<std::string> t;
t.str = "Foo";
compare<String<std::string>, Cmp1<std::string> >(s, t);
// compare(s, t);
}
Details of the code:
I have an class String, which take an parameter and create member function of that type.
I have an compare function, which takes two String& arguments. Comparison function is passed to it.
Cmp1 and Cmp2 are two compare functions.
compare<String<std::string>, Cmp1<std::string> >(s, t);
does not get compile here. I tried some other ways to call but in vain.
Looks like you want something like that:
#include <iostream>
#include <string>
template<class T>
class String {
public:
T str;
String() { std::cout << "Ctor called" << std::endl; }
};
template<class T, class C>
int compare(const String<T> &str1,
const String<T> &str2) {
for (int i = 0; (i < str1.str.length()) && (i < str2.str.length()); ++i) {
if (C::eq(str1.str[i], str2.str[i])) {
return false;
}
}
return true;
}
template<class T>
class Cmp1 {
public:
static int eq(T a, T b) { std::cout << "Cmp1 called" << std::endl; return a==b; }
};
template<class T>
class Cmp2 {
public:
static int eq(T a, T b) { std::cout << "Cmp2 called" << std::endl; return a!=b; }
};
int main() {
String<std::string> s;
s.str = "Foo";
String<std::string> t;
t.str = "Foo";
compare<std::string, Cmp1<char> >(s, t);
// compare(s, t);
}
code
Explanations:
You already have String in definition of compare, you need to just send T which is std::string in your case.
You are trying to go through entire std::string, in compare, so, now your code compiles.
You calling cmp on str[index], that is actually char, so you need to call cmp with char template argument.
i have tried to implement (kind of :) Initializer lists in older version of c++. like below..
#include <vector>
#include <cstdarg>
#include <iostream>
using namespace std;
template <class T>
vector <T> VEC_VA(size_t argCount,T arg1, ... )
{
va_list arguments;
vector <T> sList;
va_start ( arguments, argCount);
for ( int x = 0; x < (int)argCount; x++ )
sList.push_back(va_arg ( arguments, T));
va_end ( arguments );
return sList;
}
struct Test
{
Test(int _x,std::string _s):x(_x),s(_s){}
int x;
std::string s;
};
void methodWithArgs(vector<Test> testObjs)
{
cout<<"Size:"<<testObjs.size()<<endl;
for (std::vector<Test>::const_iterator it = testObjs.begin();it != testObjs.end();++it)
std::cout << it->x <<":"<< it->s.c_str()<< std::endl;
}
int main()
{
methodWithArgs(VEC_VA(2,Test(1,"one"),Test(2,"two")));
return 0;
}
But this kind of implementation works in Visual studio 2012 (v11.0). But not in Linux g++ compiler. And ended with an Error: "cannot pass objects of non-trivially-copyable type ‘struct Test’ through ‘...’"
So is there any better idea?
If you are willing to accept a slightly different syntax then all you need is a version of vector::push_back() that returns a reference to the vector. Something like this:
#include <vector>
#include <iostream>
template<typename T>
class VEC_VA_HELP {
std::vector<T> vector;
public:
VEC_VA_HELP(T arg1) : vector() { vector.push_back(arg1); }
VEC_VA_HELP &operator()(T arg) { vector.push_back(arg); return *this; }
operator std::vector<T> &() { return vector; }
};
template<typename T>
VEC_VA_HELP<T> VEC_VA(T arg1) { return VEC_VA_HELP<T>(arg1); }
struct Test {
Test(int _x) : x(_x) {}
int x;
};
void methodWithArgs(std::vector<Test> const &testObjs) {
std::cout << testObjs.size() << std::endl;
for (std::vector<Test>::const_iterator it = testObjs.begin();
it != testObjs.end();
++it)
std::cout << it->x << std::endl;
}
int
main(void)
{
methodWithArgs(VEC_VA(Test(1))(Test(2))(Test(3)));
return 0;
}
Also recursive templates come to mind but I am not sure how clean the syntax would be with them. See also this question about overloading the comma operator.
Same as like this above answer by daniel But some improvements
template <class T>
class VECS
{
vector <T> vec;
public:
VECS(){}
VECS(T t){vec.push_back(t);}
VECS& operator()(const T& t){vec.push_back(t);return *this;}
typedef VECS<T> myVECS;
myVECS& operator<< (const T& t){vec.push_back(t);return *this;}
operator vector<T>() const {return vec;}
};
Usage
methodWithArgs(VECS<Test>(Test(1,"one"))(Test(2,"two")));
methodWithArgs(VECS<Test>()<<Test(1,"one")<<Test(2,"two"));
methodWithArgs(VECS<Test>(Test(0,"zero")) <<Test(1,"one")<<Test(2,"two"));
std::vector<int> v1 = VECS<int>() << 1 << 2 << 3;
std::vector<int> v2 = VECS<int>(1)(2)(3);
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;
}
}
For example, I have a class
struct A {int a; bool b;};
And I want to generate a template function to get its elements (like the std::get to get a tuple element)
template<unsigned i, class T>
auto Get(T& t);
template<>
int& Get<0, A>(A& a)
{
return a.a;
}
template<>
bool& Get<1, A>(A& a)
{
return a.b;
}
int main()
{
A a;
Get<0>(a) = 10;
Get<1>(a) = true;
return 0;
}
The above code doesn't work. The challenge is that I don't know the returned type of Get for arbitrary class. Any way to implement it? Thanks.
Assuming you wouldn't mind making this in a "manual manner" you can do this really simply.
#include <tuple>
struct A {
int a; bool b;
};
template<size_t N>
auto get(A& a) -> decltype(std::get<N>(std::tie(a.a, a.b))) {
return std::get<N>(std::tie(a.a, a.b));
}
#include <iostream>
int main() {
A a;
get<0>(a) = 10;
get<1>(a) = true;
std::cout << a.a << '\n' << a.b;
}
Output:
10
1