..
..
..
const int sizes = 50;
template<class T>
class List {
private:
int curSize;
T arr[sizes];
public:
List<T>(){
cout << "constructor called\n";
this->curSize = 0;
}
void add(T element) {
arr[curSize] = element;
this->curSize++;
}
..
..
..
T operator[](int i){
if( i > sizes ){
cout << "Index out of bounds" << endl;
return arr[0];
}
return arr[i];
}
when i call the add function the operator overloading isnt working for me, only when i try to acces it from the main.cpp it works.
how can i acces the operator inside the class?
i searched here and i found a soulotion that didnt worked for me (*this).
The solution you found using (*this) was correct but your operator[] returns the wrong type so there would be no correct way to use it. Change the return from T to T&:
T& operator[](int i){
if( i > sizes || i<0 ){
cout << "Index out of bounds" << endl;
return arr[0];
}
return arr[i];
}
Then you can use it inside your class with:
(*this)[curSize] = element;
You should also have a const version:
T const& operator[](int i) const {
if( i > sizes || i<0 ){
cout << "Index out of bounds" << endl;
return arr[0];
}
return arr[i];
}
An alternate way to code the const and non const versions (to avoid the duplicated code) would be for one to delegate to the other using const_cast.
Also notice the need for checking i<0. That is a reason it would have been better for both i and sizes to be unsigned to avoid the extra check. The optimizer should fix the apparent inefficiency of the extra check, even if you leave the type signed. But the extra check still clutters the source code and forgetting it (as you did) is still an easy mistake. So using int for values which are never correctly negative is bad practice.
Related
I have this code
template<typename firstType,typename secondType>
struct bpair{
firstType first;
secondType second;
bpair(firstType firstNew,secondType secondNew) {
first = firstNew;
second = secondNew;
}
variant<firstType,secondType> operator[](size_t index) {
if(index == 0) {
return first;
}
return second;
}
};
bpair<string,int> hey = bpair(string("hi"),34);
cout << get<string>(hey[0]);
It is just a custom std::pair. Is there a way to load info from the pair using just the [] operator like this?
cout << hey[0];
A function can have only one return type. The return type cannot depend on a runtime parameter passed to the function.
Your cout << get<string>(hey[0]); selects at compile time that you want to retrieve the std::string member from the std::variant.
It is not (easily) possible to make this possible
cout << hey[0];
When hey[0] and hey[1] are supposed to call the same function.
You could let hey return some proxy type that when piped to std::cout selects the right member. Eventually, this would use again std::variant or similar under the hood (and require some boilerplate for not much gain).
For a solution that selects the member to be returned at compile time I repeat a solution suggested by Jarod42:
template <std::size_t I>
auto& operator[](std::integral_constant<std::size_t, I>) {
if constexpr {I == 0} { return first; }
else { return second; }
}
std::cout << hey[0_c] << " " << hey[1_c];
Note that hey[0_c] and hey[1_c] are calling two different instantiations of the template. Each with a different return type.
I am implementing a device_vector in Cuda and i am taking ideas from the well known library Thust.
Now for accessing and modifying an element in that device_vector (v), I need to do v[N] = x. For that i need to overload the [] operator.
This is the code used to overload the [] operator :
T& operator[] (unsigned int index)
{
if (index >= numEle)
return ptr[0];
else
return ptr[index];
}
The problem is : To modify any memory location in Device Memory, we need to make a Cuda Kernel Call and a Cuda kernel call cannot return anything.
As far the [] overloading is concerned it returns the reference to the element we want to modify.
How can we do this for a Cuda Kernel ?
Note : I know Thrust Library somehow does this but I am not able to understand how.
The comments have very good pointers, but as an example, you can create an object that will allow you to use the [] operator to write to the CUDA array directly (or do any other things you choose):
struct CudaVector {
unsigned int get(unsigned int index) {
cout << "Get from device: " << index << endl;
return 0; // TODO read actual value
}
void set(unsigned int index, unsigned int value) {
cout << "Set in device: " << index << " " << value << endl;
// TODO write actual value
}
struct Item {
CudaVector& vector;
unsigned int index;
operator unsigned int() const {
return vector.get(index);
}
unsigned int operator=(unsigned int other) {
vector.set(index, other);
return other;
}
unsigned int operator=(const Item& other) {
return (*this = static_cast<unsigned int>(other));
}
};
Item operator[](unsigned int index) {
return Item{*this, index};
}
};
This works like:
CudaVector vector;
unsigned int foo = vector[8];
vector[5] = vector[6] = vector[7];
Output:
Get from device: 8
Get from device: 7
Set in device: 6 0
Set in device: 5 0
Idea is that your operator[] doesn't return a reference, but instead it returns a temporary object that is able to handle 'reads' (using the conversion operator) and 'writes' (using the assignment operator).
(The second overload is there to allow chained assignments, since the first one won't be picked up automatically if you don't assign from unsigned int first.)
I'm playing around with composition, and in one of my classes I have a wrapper around the subscript operator "[ ]" (from std::vector). However, the compiler (g++) gets mad when I say this->[i]. I've worked around this issue by using (*this)[i] instead, but I thought these were synonyms. What am I missing? Here is a small sample code that throws the error (I'm purposely avoiding iterators in newmethod just to simply illustrate my problem).
#include <vector>
#include <iostream>
class A {
private:
std::vector<int> rep;
public:
std::size_t size() { return rep.size(); }
int& operator[](std::size_t index) { return rep[index]; }
void newmethod();
A(size_t n, int m) : rep(n,m) {}
};
void A::newmethod() {
for (std::size_t i=0; i < (this->size()); ++i) {
std::cout << (*this)[i] << " ";
}
for (std::size_t i=0; i < (this->size()); ++i) {
std::cout << this->[i]; << " "; //Causes an error!
}
return;
}
int main() {
A(17,3).newmethod();
return 0;
}
You have to call the operator[] member function directly, something like:
this->operator[](i)
a->b is equivalent to (*a).b. What exactly do you expect to happen when you say a->[b] and it translates to (*a).[b]?
That is not correct, if we look at the draft C++ standard we can see that E1->E2 is equivalent to (*(E1)).E2 and not (*E1)E2, this is covered in section 5.2.5 Class member access paragraph 2:
[...]The expression E1->E2 is converted to the equivalent form (*(E1)).E2;[...]
so what follows -> has to be a member of the class(or a base class), so in this case that would be operator[]:
this->operator[](i)
I have a class that I use to keep track of the values assumed by a variable. I implemented it by overloading operator=.
Usage example:
myType var0;
var0 = 1;
var0 = 3;
generates on stdout:
1
3
This works fine with variables, but not with arrays. How can I extend this feature?
One way would be overloading the [] operator to return a "proxy" - an object that references your variable, and overloads the = operator to do the tracking.
Here is a sample implementation:
#include <iostream>
using namespace std;
struct myArray;
class proxy {
myArray &array;
int index;
public:
proxy(myArray &_array, int _index)
: array(_array)
, index(_index) {
}
proxy& operator=(int value);
operator int() const;
};
struct myArray {
int data[100];
proxy operator[](int index) {
return proxy(*this, index);
}
};
proxy& proxy::operator=(int value) {
cout << "Asigning " << value << " to element " << index << endl;
array.data[index] = value;
return *this;
}
proxy::operator int() const {
cout << "Reading element at " << index << endl;
array.data[index];
}
int main() {
myArray a;
a[5] = 123;
a[8] = 321;
int x = a[5];
return 0;
}
This prints
Asigning 123 to element 5
Asigning 321 to element 8
Reading element at 5
What you want to do is to use a proxy class for your array and on that class define an operator[] function. Much like how std::vector does it.
You would trace when a non-const reference is produced to an array element. I think that you'd have to assume it was about to be written to. You would make the array out of your existing class so that you'd see the actual write.
The output might look like:
ref to element 32: write 1
Or however you would like it.
Well, arrays don't support operator= anyway, so that is not a real a problem. You can assign to individual array elements of course, but that's already covered by your existing operator=.
You could create a MyArrayType that overloads the [] operator to store the values internally within an array of MyTypes
I want to access the vector in the "manipulatevector" function below the same way as i access an array with vector[i] and not vector->at(i) in the code below. I have tried to pass the vector directly, and not a pointer as can be done with arrays. But this seem to corrupt the program. Any ideas how this can be achieved? Im new to using the std library, as i mostly have experience from C.
#include <vector>
#include <iostream>
#define vectorsize 5
struct st_test {
int ii;
float dd;
};
void manipulatevector(std::vector<struct st_test> *test) {
test->resize(vectorsize);
for(int i=0;i<vectorsize;i++) {
test->at(i).dd = i*0.4f;
test->at(i).ii = i;
}
}
void manipulatearray(struct st_test test[vectorsize]) {
for(int i=0;i<vectorsize;i++) {
test[i].dd = i*0.4f;
test[i].ii = i;
}
}
void main() {
std::vector<struct st_test> test1;
manipulatevector(&test1);
struct st_test test2[vectorsize];
manipulatearray(test2);
std::cout << "Vector" << std::endl;
for(int i=0;i<vectorsize;i++) {
std::cout << test1.at(i).dd << std::endl;
}
std::cout << "Array" << std::endl;
for(int i=0;i<vectorsize;i++) {
std::cout << test2[i].dd << std::endl;
}
}
Have you tried passing the vector as a reference?
void manipulatevector(std::vector<struct st_test> &test) {
test.resize(vectorsize);
for(int i=0;i<vectorsize;i++) {
test[i].dd = i*0.4f;
test[i].ii = i;
}
}
and
std::vector<struct st_test> test1;
manipulatevector(test1);
You can simply use (*test)[i] instead of test->at(i).
This is not actually the same behavior (at vs operator[]), but you are probably already aware of that.
Pass it as a reference instead of a pointer.
void manipulatevector(std::vector<struct st_test> &test) {
You then use . instead of ->, and things like the overloaded [] operator are usable.
Change the signature of void manipulatevector(std::vector<struct st_test> *test) to void manipulatevector(std::vector<struct st_test>& test). Then you can use the operator[] on the vector.
You can pass the vector by reference and use the [] operator:
void manipulatevector(std::vector<struct st_test>& test) {
test.resize(vectorsize);
for(int i=0;i<vectorsize;i++) {
test[i].dd = i*0.4f;
test[i].ii = i;
}
}
When you passed the vector directly, I presume you passed it by value:
void manipulatevector(std::vector<struct st_test> test) {
which meant any changes made inside manipulatevector() would not be seen by the caller. This would mean:
for(int i=0;i<vectorsize;i++) {
std::cout << test1.at(i).dd << std::endl;
}
would throw a std::out_of_range error, from test.at(i), as test1 would not have vectorsize elements, but zero elements. As there is no exception handling in main() this would have caused the program to crash.
There are different options here. You can pass the vector by reference, which is the simplest and cleaner in code:
void function( std::vector<type>& v )
Now, in some shops the style guide requires that if you are going to modify an argument you pass it by pointer as that makes it explicit at the place of call. In that case there are different options to call operator[]:
void function( std::vector<type> *v ){
(*v)[0] = .... // dereference first
v->operator[](0) = .... // explicitly cal the operator
std::vector<type>& vr =*v;
vr[0] = .... // create reference and use that
The first two are equivalent, with the first being arguably easier to read. The second is equivalent to the first one in that it dereferences the pointer and then accesses the operator, but you are explicitly giving a name to the reference, so it can be reused in the function without having to dereference in all uses. While this technically creates an extra variable, the compiler will most probably optimize the reference away.