How to overload subscript operator [] to reference 2d STL array? - c++

I am trying to create an overloaded operator for my class, my class contains a 2d array container. I want use the operator as follows: fooClass a; a[i][j] = 4;
i don't want to use it like a[i, j], a(i, j) or call a function to input or output an element. Is is possible?
Chaining the call wont work since the first returns pointer to array, and the second should return an element in an array i.e. a float.
my class looks something like this:
class foo
{
public:
foo();
~foo();
foo& operator=(const foo&rhs);
foo& operator=(const foo&&rhs);
foo& operator=(std::initializer_list<std::initializer_list<float>> il);
friend std::ostream& operator<<( std::ostream& os, const foo&rhs);
std::array<float, 3>& operator[](const int & rhs); <<<<HERE<<<< What should it return?
private:
std::array<std::array<float, 3>, 3> matrix;
};
int main()
{
foo a;
a = {{1,2,3},{4,5,6},{7,8,9}};
a[1][2] = 13;
cout << a[1][2] << endl;
return(0);
}
My question is, how to do this, and what should the function ..... operator[](const int & rhs); return?
FYI I am not using the array container directly because I am implementing other functions also I am doing the matrix column major.

Doesn't this work?
std::array<float, 3>& operator[](const int & rhs) {
return matrix[rhs];
}

Related

C++ What operators I need to overload to make this A1 += A2 * floatValue work?

What operators I need to overload to make this word?
Variables A1 and A2 both of type class A, variable floatValue is of type float.
A1 += A2 * floatValue;
I have overloaded this operators
A operator+() const;
A operator+=(const A value);
A operator*(const A value);
friend A operator*(const A val2, float val);
But, I receive error "Class A has no suitable copy constructor"
I have this constructors in my class
A();
A(float val1, float val2);
A(float value);
Thanks for answering.
Minimal example:
#include <iostream>
using namespace std;
struct foo {
float val;
foo(float val): val(val){}
foo &operator+=(foo const &other) {
this->val += other.val;
return *this;
}
friend foo operator*(foo const &lhs, foo const &rhs) {
return lhs.val*rhs.val;
}
};
int main() {
foo a = 5, b = 6;
a += b * 3;
cout << a.val << endl;
return 0;
}
see: http://ideone.com/6pD2pr
With an explicit constructor you might want to use this example instead:
#include <iostream>
using namespace std;
struct foo {
float val;
explicit foo(float val): val(val){}
foo &operator+=(foo const &other) {
this->val += other.val;
return *this;
}
friend foo operator*(foo const &lhs, float val) {
return foo(lhs.val*val);
}
};
int main() {
foo a(5), b(6);
a += b * 3;
cout << a.val << endl;
return 0;
}
see: http://ideone.com/o8Vu1d
Whenever you overload an assignment operator like
A operator+=(const A value);
you also need to define a copy constructor like
A( const A& );
The copy constructor will be used by the assignment operator.
This is part of what's known as the Rule of Three.
When you have function like this:
fun(A a);
Arguments here are passed by value, so you need to have copy constructor for A (in order to create new instance from another instance), OR you can change it to reference, so no copy constructor will be needed.
Like this:
A operator+=(const A &value);

Operator overloading as friend function error

I'm trying to use + to add 2 vector (mathematical vector). Here's my code:
class Vector{
double v[Max_size];
int dim;
public:
int getDim() const;
Vector();
Vector(int n);
Vector(const Vector& a);
Vector add(const Vector&b);
friend Vector operator+(Vector summand1, Vector summand2);
};
Operator overloading:
Vector operator+(Vector summand1, Vector summand2){
int dim1 = summand1.getDim();
int dim2 = summand2.getDim();
assert(dim1 == dim2);
Vector sum(dim1);
int i;
for(i = 0; i < dim1; i++){
sum.v[i] = summand1.v[i] + summand2.v[i];
}
return sum;
}
And how I use it:
Vector m = v+t;
When I run the code, it always shows that m is (0,0) (2D vector), which is the default value generated by the constructor. What's wrong with it? Thanks!
Your copy constructor:
Vector::Vector(const Vector& a){
dim = a.dim;
Vector(dim);
}
correctly sets the value of the dim member, but has not other side effect.
You should have a variant of the following code:
Vector::Vector(const Vector& a) : dim(a.dim) {
std::copy(std::begin(a.v), std::end(a.v), v);
}
This will actually copy the data present in the parameter, and you will see the correct behavior for the code:
// Copy constructor called here, but did not correctly copy the data before.
Vector m = v + t;
For a better (by that I intend simpler and safer) Vector class, if you have access to a compiler that is at least C++11 compliant, you can write:
class Vector{
std::array<double, Max_size> v; // Note the std::array here.
int dim;
public:
int getDim() const;
Vector();
Vector(int n);
Vector(const Vector& a);
Vector add(const Vector&b);
friend Vector operator+(Vector summand1, Vector summand2);
};
The std::array will take care of everything, provided you write your copy constructor like this:
Vector::Vector(const Vector& a) : v(a.v), dim(a.dim) {
}
Or, even better, you could then let the compiler generate the copy constructor itself, with the same behavior.

Using ostream_iterator and operator << to display a vector of pointers

I'm trying to display a vector of pointers on objects using ostream_iterator and the operator <<. Thus, I override the operator <<. The problem that I always get the vector elements address. How do I make the iterator to print the actual values? Do I need to specialize it?
class A {
private:
double x;
long y;
public:
A(long xx, double yy) :x(xx), y(yy){};
~A();
void Display();
};
template<typename T>
std::ostream &operator <<(std::ostream &os, const std::vector<T> &v) {
using namespace std;
copy(v.begin(), v.end(), ostream_iterator<T>(os, "\n"));
return os;
}
int main()
{
std::vector<A*> aVect;
FillA(aVect);
cout << accountVect;
return 0;
}
//
output
00657990
006579D0
00657A48
You could write an operator<< overload for A*, but it'd be slightly nicer to dereference the pointer first, like:
template<typename T>
std::ostream &operator <<(std::ostream &os, const std::vector<T *> &v) {
std::transform(v.begin(), v.end(),
ostream_iterator<T>(os, "\n"),
[](T const *ptr) -> T const& { return *ptr; }
);
return os;
}
and then write the usual operator<< overload for A.
Note - as #WhozCraig mentioned in comments, your existing code isn't printing the vector element's address, it's printing the vector element as you asked, and that element is an address. The simplest possible fix would be to just use a vector<A> in the first place, if you can.
However, I've assumed you need to keep the vector<A*> and want to print the dereferenced A objects.
Also, I've stuck with your original template, but it's not entirely clear whether a non-templated operator<<(ostream&, vector<A*> const &) would be cleaner.
I've a bit modified your code to work:
#include <functional>
class A {
public:
A(){ x = 5; y = 5;}
A(long xx, double yy) :x(xx), y(yy){};
~A();
void Display() {
std::cout << "X: " << x << " | Y: " << y << std::endl;
}
double x; // made this public just not to create an accessor
long y;
};
template<typename T>
std::ostream &operator <<(std::ostream &os, const std::vector<T*> &v) {
std::transform(v.begin(), v.end(), std::ostream_iterator<decltype(T::x)>(os, "\n"), [](const T* t){return t->x;});
// or use A::Display() method with std::bind
std::for_each(v.begin(), v.end(), std::bind(&A::Display, std::placeholders::_1));
// or with std::mem_fn
std::for_each(v.begin(), v.end(), std::mem_fn(&A::Display));
return os;
}
int main()
{
std::vector<A*> aVect = {new A, new A, new A};
std::cout << aVect;
return 0;
}
So the first problem is that you need to specialize properly:
std::ostream &operator <<(std::ostream &os, const std::vector<T*> &v) {
instead of
std::ostream &operator <<(std::ostream &os, const std::vector<T> &v) {
This is because you have array of pointers but your current specialization works for non-pointer objects of vector.
Next, I've modified your std::copy call because will not work ever until you provide a operator<< overload for your class A. So, I've changed it to std::transform to be able to output your values.
UPD: also, here is a way to use your A::Display() method with std::for_each algorithm with use std::bind or std::mem_fn functional objects.
Considering that std::ostream_iterator itself uses operator<< for the output, you can solve this easily by doing another overload:
std::ostream& operator<<(std::ostream& os, A const* a)
{
// Some output of `a` here
return os;
}

Efficient vector operators in C++ / References to temporary objects

I am trying to write a C++ vector class that stores an array of data and allows performing mathematical operations on an element-by-element basis. I want to implement this in such a way that an expression a = b + c + d should loop over all elements only once and directly write the sum b[i] + c[i] + d[i] to a[i] without creating intermediate vectors.
I was writing something like this:
template<class T, int N>
class VectorExpression {
public:
virtual T operator[] (int i) const = 0;
virtual ~VectorExpression() {}
}
template<class T, int N>
class MyVector : public VectorExpression<T, N> {
T data[N];
public:
T& operator[] (int i) { return data[i]; }
T& const operator[] (int i) const { return data[i]; }
MyVector<T,N>& operator=(const VectorExpression<T,N> &rhs) {
for (int i = 0; i < N; ++i)
data[i] = rhs[i];
return *this;
}
}
template<class T, int N>
class VectorSum : public VectorExpression<T, N> {
VectorExpression<T,N> &a, &b;
public:
VectorSum(VectorExpression<T,N> &aa, VectorExpression<T,N> &bb)
: a(aa), b(bb) {}
T operator[] (int i) const { return a[i] + b[i]; }
}
template<class T, int N>
VectorSum<T,N> operator+(const VectorExpression<T,N> &a,
const VectorExpression<T,N> &b)
{
return VectorSum<T,N>(a, b);
}
int main() {
MyVector<double,10> a, b, c, d;
// Initialize b, c, d here
a = b + c + d;
return 0;
}
Probably this functionality is provided by the valarray class but that's because I tried to strip it down to a minimal example.
I made operator[] virtual because this allows nesting all kinds of expressions (e.g. a = !(-b*c + d)) provided I would define all the operators and the corresponding classes similar to VectorSum.
I use references because ordinary variables aren't polymorphic and pointers don't work with operator overloading.
Now my questions about this are:
In the statement a = b + c + d;, two temporary VectorSum<double,10> objects will be created to store b + c and (b+c) + d respectively. Will they live long enough to make the polymorphic behavior work? More specifically, (b+c) + d will store a reference to b + c, but will that object still exist when operator= is called? According to this post all temporaries should exist until operator= returns, but does this also hold for older versions of C++?
If not, then how is this done? The only alternative I see would be to allocate the VectorSum objects using new, return them by reference and then delete them in the operator= functions, but that seems a little cumbersome, and probably a lot less efficient. I'm also not sure if it is always safe.
(Minor question) Is it okay to override the return type T of VectorExpression::operator[] by T& const in MyVector?
EDIT
I had wrong argument types in operator+: changed them from VectorSum to VectorExpression.
Well here's what I came up with:
#include <iostream>
#include <initializer_list>
#include <algorithm>
template<class T, int N>
class VectorExpression {
public:
virtual T operator[] (int i) = 0;
virtual const T operator[] (int i) const = 0;
virtual ~VectorExpression() {}
};
template<class T, int N>
class MyVector : public VectorExpression<T, N> {
T data[N];
public:
MyVector() {
// initialize zero
std::fill(std::begin(data), std::end(data), T());
}
MyVector(const std::initializer_list<T>& values) {
// initialize from array initializer_list
std::copy(std::begin(values), std::end(values), data);
}
MyVector(const VectorExpression<T,N>& rhs) {
for (int i = 0; i < N; ++i)
data[i] = rhs[i];
}
MyVector<T,N>& operator=(const VectorExpression<T,N>& rhs) {
for (int i = 0; i < N; ++i)
data[i] = rhs[i];
return *this;
}
T operator[] (int i) { return data[i]; }
const T operator[] (int i) const { return data[i]; }
friend std::ostream& operator<<(std::ostream& stream, MyVector& obj) {
stream << "[";
for (int i = 0; i < N; ++i) {
stream << obj.data[i] << ", ";
}
stream << "]";
return stream;
}
};
template<class T, int N>
class VectorSum : public VectorExpression<T, N> {
const MyVector<T,N> &a, &b;
public:
VectorSum(const MyVector<T,N>& aa, const MyVector<T,N>& bb):
a(aa), b(bb) {
}
T operator[] (int i) { return return a[i] + b[i]; }
const T operator[] (int i) const { return a[i] + b[i]; }
};
template<class T, int N>
MyVector<T,N> operator+(const MyVector<T,N>& a, const MyVector<T,N>& b) {
return VectorSum<T,N>(a, b);
}
int main() {
MyVector<double,3> a, b({1,2,3}), c({3,4,5}), d({4,5,6});
a = b + c + d;
std::cout << b << std::endl;
std::cout << c << std::endl;
std::cout << d << std::endl;
std::cout << "Result:\n" << a << std::endl;
return 0;
}
Output:
[1, 2, 3, ]
[3, 4, 5, ]
[4, 5, 6, ]
Result:
[8, 11, 14, ]
I've added an initializer_list (C++11) constructor and ostream operators purely for convenience/illustration purposes.
Since you've defined the operator[] as return by value, I was unable to set items in the data array for testing (since error: lvalue required as left operand of assignment); typically this operator should be by reference - but then, in your case, VectorSum::operator[] wouldn't work because that would fail compilation because of returning a reference to a temporary.
I also added a copy constructor because ...
// this calls MyVector's copy constructor when assigned to 'main::a'
template<class T, int N>
MyVector<T,N> operator+(const MyVector<T,N>& a, const MyVector<T,N>& b) {
return VectorSum<T,N>(a, b); // implicit MyVector::copy constructor
}
// this also calls MyVector's copy constructor (unless the copy constructor is defined explicit)
template<class T, int N>
MyVector<T,N> operator+(const MyVector<T,N>& a, const MyVector<T,N>& b) {
MyVector<T,N> res = VectorSum<T,N>(a, b);
return res;
}
// but this would call MyVector's assignment operator
template<class T, int N>
MyVector<T,N> operator+(const MyVector<T,N>& a, const MyVector<T,N>& b) {
MyVector<T,N> res;
res = VectorSum<T,N>(a, b);
return res;
}
In answer to your questions:
Yes - how would it behave if you explicitly defined the variable and
returned that? It's the same behaviour for temporaries, except there
is no variable declaration;
n/a
I touched on this above - you can't
use reference because of 'returning reference to temporary' error;
However there's no reason why you can add T& operator[] to MyVector( ie. not overriding).
EDIT: answers to comments:
The function specification must be identical when overriding including return type. Since you have defined it return by value in VectorExpression it must be return by value in MyVector. If you try to change it to reference in the child class you will get a compile error: conflicting return type specified. So no you can't override operator const with a version that returns const T& instead of T. Furthermore it must return by value since MyVectorSum returns { a[i] + b[i] } which would be a temporary and you can't return a reference to a temporary.
Sorry my mistake, fixed above.
because:
MyVector isn't a subtype of VectorSum - compile error ‘MyVector’ is not derived from ‘const VectorSum’
I've also tried with VectorExpression but compile error: 'cannot allocate an object of abstract type' - because it's trying to return by value
I chose MyVector since that's the type of your expected result. Yes it does those all those for loops but I can't see a way round that : there's three different array 'data' variables each of which need to be iterated into order to be accumulated. At some point in the code you will have to do the for loops.
Understood, yes I got confused. removed from post.
I didn't think of this at first but having a virtual operator[] method probably kills the efficiency I was trying to achieve by avoiding the 3 for-loops and intermediate storage of vector-sized temporaries. Making a method virtual prevents it from being inlined, which means it needs to be actually called as a function everytime an element is accessed.
Based on links I got from people who commented to my question and from Google, I ended up with the following solution which avoids needing any virtual methods.
template<class T, int N, class V>
class VectorExpressionBase {
V ref;
protected:
explicit VectorExpressionBase(const V *ref)
: ref(const_cast<V*>(ref)) {}
public:
T operator[] (int i) const { return ref[i]; }
T& operator[] (int i) { return ref[i]; }
};
template<class T, int N>
class VectorExpressionBase<T,N,void> {
T data[N];
protected:
explicit VectorExpressionBase(const void*) {
// Argument is unused but accepted to have uniform
// calling syntax
}
public:
T operator[] (int i) const { return data[i]; }
T& operator[] (int i) { return data[i]; }
};
template<class T, int N, class V>
class VectorExpression : public VectorExpressionBase<T,N,V> {
public:
template<class V1>
VectorExpression<T,N,V>& operator= (
const VectorExpression<T,N,V1> &rhs)
{
for (int i = 0; i < N; ++i)
data[i] = rhs[i];
return *this;
}
explicit VectorExpression(const V *ref = 0)
: VectorExpressionBase<T,N,V>(ref) {}
// Can define all kinds of operators and functions here such as
// +=, *=, unary + and -, max(), min(), sin(), cos(), ...
// They would automatically apply to MyVector objects and to the
// results of other operators and functions
};
template<class T, int N>
class MyVector : public VectorExpression<T,N,void> {
};
template<class T, int N, class VA, class VB>
class VectorSum {
VectorExpression<T,N,VA> &a;
VectorExpression<T,N,VB> &b;
public:
VectorSum(VectorExpression<T,N,VA> &aa, VectorExpression<T,N,VB> &bb)
: a(aa), b(bb) {}
T operator[] (int i) const { return a[i] + b[i]; }
};
template<class T, int N, class VA, class VB>
VectorExpression<T,N,VectorSum<T,N,VA,VB> >
operator+(const VectorExpression<T,N,VA> &a,
const VectorExpression<T,N,VB> &b)
{
VectorSum<T,N,VA,VB> sum(a, b);
return VectorExpression<T,N,VectorSum<T,N,VA,VB> >(sum);
}
Class VectorExpression now just wraps the class that does the work (in this case VectorSum). This allows defining all kinds of functions and operators for VectorExpression only, rather than having to overload them for VectorSum, VectorProduct, etc.
MyVector derives from a special case of VectorExpression which has a specialized base class; this isn't really necessary but it's nice because it makes all functions and operators defined for VectorExpression also available for MyVector. By using a simple base class VectorExpressionBase that only deals with storage and the [] operator, all other operators and methods don't need to be duplicated in the specialization for V = void.
Users would only need to know about classes MyVector<T,N> (for storing data) and possibly about VectorExpression<T,N,V> if they want to define additional functions and operators. VectorExpressionBase and the classes like VectorSum don't need to be visible to the outside world.
I find my original solution somewhat cleaner conceptually because the meaning of each class is more clear and because it doesn't require the template parameter V, but this one is more efficient because it doesn't require any virtual functions, which can probably make a large difference in certain cases.
Thanks for pointing me to the right links!
P.S. Surely most / all of this isn't new but I thought it would be nice to summarize and explain it a bit. I hope it can help others.
EDIT
I changed the type of data member VectorExpressionBase<T,N,V>::ref from V& to V. This is needed since the temporary V object the reference was pointing at may no longer exist at the time the VectorExpression is evaluated. For example, the temporary VectorSum object stops existing when the operator+ function returns, making the returned VectorExpression object useless.
I also completed the code with some constructors and corrected the operator+ function.

Overload operator[] for Char assignment - C++

I am fairly new to C++, although I do have some experience programming. I have built a Text class that uses a dynamic char* as it's main member. The class definition is below.
#include <iostream>
#include <cstring>
using namespace std;
class Text
{
public:
Text();
Text(const char*); // Type cast char* to Text obj
Text(const Text&); // Copy constructor
~Text();
// Overloaded operators
Text& operator=(const Text&);
Text operator+(const Text&) const; // Concat
bool operator==(const Text&) const;
char operator[](const size_t&) const; // Retrieve char at
friend ostream& operator<<(ostream&, const Text&);
void get_input(istream&); // User input
private:
int length;
char* str;
};
The issue I am having is I don't know how to use operator[] to assign a char value at the given index that's passed in. The current overloaded operator operator[] is being used to return the char at the index supplied. Anyone have experience with this?
I would like to be able to do something similar to:
int main()
{
Text example = "Batman";
example[2] = 'd';
cout << example << endl;
return 0;
}
Any help and/or advice is appreciated!
Solution provided - Thanks a bunch for all the replies
char& operator[](size_t&); works
You need to provide a reference to the character.
#include <iostream>
struct Foo {
char m_array[64];
char& operator[](size_t index) { return m_array[index]; }
char operator[](size_t index) const { return m_array[index]; }
};
int main() {
Foo foo;
foo[0] = 'H';
foo[1] = 'i';
foo[2] = 0;
std::cout << foo[0] << ", " << foo.m_array << '\n';
return 0;
}
http://ideone.com/srBurV
Note that size_t is unsigned, because negative indexes are never good.
This article is the definitive guide to operator overloading in C++ (which, to be honest, is mainly boilerplate code for syntactic sugar). It explains everything that is possible:
Operator overloading
Here's the portion that is of interest to you:
class X {
value_type& operator[](index_type idx);
const value_type& operator[](index_type idx) const;
// ...
};
And yes, this is possible, for the many of the STL containers (the vector for example), allow for array subscript notation to access data.
So you can do something along the lines of this:
char & operator[]( size_t i )
{
return *(str + i);
}
You should overload operator[] as non const method and return a reference from it
char& operator[](const int&);