given the following template function :
template <class T>
void DoSomething(T &obj1, T &obj2)
{
if(obj1 > obj2)
cout<<"obj1 bigger: "<<obj1;
else if(obj1 == obj2)
cout<<"equal";
else cout<<"obj2 bigger: "<<obj2;
T tmp(3);
T array[2];
array[0]=obj1;
array[1]=obj2;
}
I need to define a class called MyClass (declarations only , i.e. just the .h file) , that would be able to work with that template function .
I defined the next declarations :
class MyClass
{
public:
MyClass(); // default ctor
MyClass(int x); // for ctor with one argument
bool operator ==(const MyClass& myclass) const;
bool operator >(const MyClass& myclass) const;
friend ostream& operator<<(ostream &out,const MyClass& myclass); // output operator
};
What I don't understand is why there is no need to define operator [] for the lines:
array[0]=obj1; array[1]=obj2;
? When would I need to define operator []?
thanks ,Ron
You declared an array for your type:
T array[2];
But your are talking about implementing operator[] for T, which is totally different concept.
If you need
T t;
t[1] = blah
Then you need to implement operator[]
Because
T array[2];
Isn't a T object, its an array of T. So
array[0];
Is indexing an array, not one of your objects, therefore you don't need an operator[].
Assuming you call DoSomething with a couple of MyClass objects, you have declared array to be a normal array of MyClass objects. You did not need a [] operator for MyClass because array is not an instance of MyClass; it is just an array.
You will want to overload the [] operator in your own classes when it makes sense to, or is convenient. A good example is a collection (such as a map). Another example is a custom string class, where you might want to index by a regex object to find matches for your pattern inside your string.
If your class was an implementation of a dynamic array, for example, you would want to access the (single) object as though it was an array - you this by overloading the [] operator.
Related
I want to move the pointer of a vector to my the vector of the A object (this). I want to do this because I use my help vector (for mergesort) and I want the values of the help vector in the original vector. I however only want to use 1 operation (so it should be done with a move, no copying of elements).
This is the code I use:
template<class T>
class A:public vector<T> {
public:
void fillAndMove();
vector<T> help;
}
template<class T>
void A<T>:fillAndMove() {
// Fill a help array with random values
help.resize(2);
help[0] = 5;
help[1] = 3;
// This line doesn't work
*this = move(help);
}
I get following error:
no match for 'operator=' (operand types are 'A<int>' and 'std::remove_reference<std::vector<int, std::allocator<int> >&>::type {aka std::vector<int, std::allocator<int> >}')
I think the problem is that the help vector needs to be casted to a class A object but I don't know how I should do it. Anyone that can help me?
You want to implement move assigment operator, which will do it in O(1).
template<class T>
class A :public vector<T> {
public:
void fillAndMove();
vector<T> help;
A & operator=(std::vector<T> && rhs)
{
static_cast<vector<T>&>(*this) = move(rhs);
return *this;
}
};
It will allow to assign normal vectors to your A class as well though, which will keep help vector unchanged, thus you might want to make this operator private and implement move assigment operator for A class public.
test = std::vector<int>{ 5,6 }; // possible - should assigment operator be private?
Not possible with this code:
template<class T>
class A :public vector<T> {
public:
void fillAndMove();
vector<T> help;
A & operator=(A && rhs)
{
// Move as you want it here, probably like this:
help = std::move(rhs.help);
static_cast<vector<T>&>(*this) = move(rhs);
return *this;
}
private:
A & operator=(std::vector<T> && rhs)
{
static_cast<vector<T>&>(*this) = move(rhs);
return *this;
}
};
Also, when doing it you should implement move constructor as well.
You have to overload operator assignment if you want to use it that way
A & operator=(const std::vector<T> & rhs)
{
for(auto it : help)
{
this->push_back(it);
}
return *this;
}
Working example here.
Is there any way to overload the array subscript operator in C++ other than in a class? I would like to call a user-defined function when reading/writing in the array.
For example:
int* array = new int[10];
array[0] = 5;
When writing in array[0], I would like to call my own function. I know it can be done inside a class by overloading the operator[] (for example, a SafeArray class).
Thanks.
What you want is a wrapper class, something like:
template<typename T>
struct SubscriptWrapper {
SubscriptWrapper(T* array) : array_(array) {};
T& operator[](size_t index) {
// your magic goes in here
};
T* array_;
}
I'm writing a matrix class (CMatrix), with such derived classes as a 3d vector(CVector) and a rotation matrix(CRotMatrix). My CMatrix object could be multiplied by an another CMatrix-based object or by an any numerical value(scalar).
This code represents the essence of the problem I got:
template<class T> class CMatrix
{
public:
template<class U> const CMatrix& operator=(const CMatrix<U> &inp){return (*this);}
CMatrix& operator*(const CMatrix &inp)
{
cout<<"Multiplication by CMatrix"<<endl;
return (*this);
}
template<class U>
CMatrix& operator*(const U &inp)
{
cout<<"Multiplication by a scalar."<<endl;
return (*this);
}
};
template<class T> class CVector: public CMatrix<T>{};
template<class T> class CRotMatrix: public CMatrix<T>{};
int main()
{
CMatrix<int> foo1;
CMatrix<int> foo2;
CVector<int> dfoo1;
CRotMatrix<int> dfoo2;
foo1 = foo1*foo2; //calls CMatrix method
foo1 = foo1*5; //calls scalar method
foo1 = foo1*dfoo2; //calls scalar method, shoud be CMatrix
foo1 = dfoo2*dfoo1; //calss scalar method, shoud be CMatrix
return 0;
}
The problem is that the compiler prefers the template version of operator*(). Is there any way to make the compiler choose the proper method for derived CMatrix classes in this situation? If I cut off this method
CMatrix& operator*(const U &inp)
The compiler does it in the right way, but the class loses the ability to be multiplied by a scalar. I'm using msvc10. Thank you in advance.
The reason is that the template operator is considered an exact match while the matrix version requires a conversion to parent reference. Thus the compiler pick the template as a better match.
First consider if you really need the child classes that you've created and that they provide the appropriate functionality/overrides.
If you need them then I would solve the problem by making one or both of the operations not an operator. By making operator* do both kinds of multiply you violate the principle of least surprise having it do two wildly different things depending on context. I would suggest named methods for both so it's obvious, but otherwise I would suggest operator* to be matrix math and a function ScalarMultiply to do the single scalar type.
The problem is that the compiler prefers the template version of operator*(). Is there any way to make the compiler choose the proper method for derived CMatrix classes in this situation?
That's because you told it to. Your Multiplication by a scalar method is more generic than is your Multiplication by CMatrix method.
Make your "Multiplication by a scalar" method be what the comment says it is:
CMatrix& operator*(const T & inp)
{
std::cout<<"Multiplication by a scalar."<<std::endl;
return (*this);
}
Addendum
Your template<class U> CMatrix& operator*(const U &inp) is so generic that it matches anything. Multiple by a std::istream: No problem. It prints Multiplication by a scalar. You want your multiplication by a scalar to be restrictive, not a catch-all for any random type.
#include <list>
#include <set>
#include <iterator>
#include <algorithm>
using namespace std;
class MyContainer {
public:
string value;
MyContainer& operator=(const string& s) {
this->value = s;
return *this;
}
};
int main()
{
list<string> strings;
strings.push_back("0");
strings.push_back("1");
strings.push_back("2");
set<MyContainer> containers;
copy(strings.begin(), strings.end(), inserter(containers, containers.end()));
}
The preceeding code does not compile. In standard C++ fashion the error output is verbose and difficult to understand. The key part seems to be this...
/usr/include/c++/4.4/bits/stl_algobase.h:313: error: no match for ‘operator=’ in ‘__result.std::insert_iterator::operator* [with _Container = std::set, std::allocator >]() = __first.std::_List_iterator::operator* [with _Tp = std::basic_string, std::allocator >]()’
...which I interpet to mean that the assignment operator needed is not defined. I took a look at the source code for insert_iterator and noted that it has overloaded the assignment operator. The copy algorithm must uses the insert iterators overloaded assignment operator to do its work(?).
I guess that because my input iterator is on a container of strings and my output iterator is on a container of MyContainers that the overloaded insert_iterator assignment operator can no longer work.
This is my best guess, but I am probably wrong.
So, why exactly does this not work and how can I accomplish what I am trying to do?
What would work would be using the constructor (which would make more sense instead of the assignment):
class MyContainer {
public:
string value;
MyContainer(const string& s): value(s) {
}
};
Then the second problem is that set also requires its contents to be comparable.
As to the cause, insert_iterator works by overloading operator=:
insert_iterator<Container>& operator= (typename Container::const_reference value);
As you can see, the righthand value must be either the value type of the container or implicitly convertible to it, which is exactly what a (non-explicit) constructor achieves and the assignment operator doesn't.
Technically you could also make it work without changing the class (e.g if you don't want an non-explicit constructor) by providing a suitable conversion function:
MyContainer from_string(const std::string& s)
{
MyContainer m;
m = s; //or any other method how to turn a string into MyContainer
return m;
}
which can be used with std::transform:
transform(strings.begin(), strings.end(), inserter(containers, containers.end()), from_string);
You need to add:
1. Constructor that takes string (you are trying to add string to container that can contain MyContainer objects).
2. bool operator < (set uses it by default to compare elements)
For instance :
class MyContainer
{
public:
MyContainer(const string& v):value(v){};
};
bool operator <(const MyContainer &c1, const MyContainer &c2)
{
return c1.value <c2.value;
}
The problem is twofold:
You're trying to fill a set of MyContainer objects
... from a list of string objects.
The copy() algorithm tries to convert each string object to a MyContainer object. In C++ to add to class MyContainer conversion support from type string to type MyContainer you need to add a constructor that takes a parameter of type string:
struct MyContainer {
MyContainer(const string& s) : value(s) { }
bool operator<(const MyContainer& o) const { return value < o.value; }
private:
string s;
};
You don't need an assignment operator, because the compiler can get the copying done by the copy-constructor: convert a string to a MyContainer and then use the default assignment operator to assign one MyContainer object onto the other. You will, however need an operator<() because C++ sets are sorted.
I want to find in a vector of Object pointers for a matching object. Here's a sample code to illustrate my problem:
class A {
public:
A(string a):_a(a) {}
bool operator==(const A& p) {
return p._a == _a;
}
private:
string _a;
};
vector<A*> va;
va.push_back(new A("one"));
va.push_back(new A("two"));
va.push_back(new A("three"));
find(va.begin(), va.end(), new A("two"));
I want to find the second item pushed into the vector. But since vector is defined as a pointers collection, C++ does not use my overloaded operator, but uses implicit pointer comparison. What is the preferred C++-way of solutiono in this situation?
Use find_if with a functor:
template <typename T>
struct pointer_values_equal
{
const T* to_find;
bool operator()(const T* other) const
{
return *to_find == *other;
}
};
// usage:
void test(const vector<A*>& va)
{
A* to_find = new A("two");
pointer_values_equal<A> eq = { to_find };
find_if(va.begin(), va.end(), eq);
// don't forget to delete A!
}
Note: your operator== for A ought to be const, or, better still, write it as a non-member friend function.
Either use std::find_if and provide a suitable predicate yourself, see other answers for an example of this.
Or as an alternative have a look at boost::ptr_vector, which provides transparent reference access to elements which are really stored as pointers (as an extra bonus, memory management is handled for you as well)
Try using find_if instead. It has a parameter for a predicate where you can decide exactly how to check wheter you found the right element.
http://www.sgi.com/tech/stl/find_if.html
You could also use Boost::Lambda:
using namespace boost::lambda;
find_if(va.begin(), va.end(), *_1 == A("two"));
Of course, you should prefer to use shared_ptrs so you don't have to remember to delete!