Overloading Subscript operator

R

raan

What I am trying to achieve here is depicted in the small program
below.

// Wrapit.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include <map>
#include <list>

using namespace std;

class A
{

private:
string a;
string b;
string c;
public:
A(){}

};

class B
{

private:
string a;
string b;
string c;

public:
B(){cout << "B constructor is being called \n";}
};


class C
{
private:
map<string, A *> aobj;
map<string, B *> bobj;
public:

C(){cout << "Constructor of C called \n";}

template <class T>
T& operator [] (string key)
{
cout << "Operator [] called \n";
return new A(); //if the key has a particular text in it return
new A
// otherwise return new B();
}

};

int _tmain(int argc, _TCHAR* argv[])
{
C c;
c["abcd"] = new A();
c["efgh"] = new B();

return 0;
}


Obviously the above program will give you compiler errors.

I am trying to put a wrapper around the maps. And the insertion to the
maps is done through an
(eg . c["abcd"] = new A()) overloaded [] operator. Further I want to
use just one [] version of the function, but inside I will determine
whether I should return a new A() or a new B(). The string I recieved
as argument will have enough information for me to decide which object
to be returned. How would i do it.

My environment: VS2003 on Windows XP.

All your helps appreciated
 
?

=?ISO-8859-1?Q?Erik_Wikstr=F6m?=

What I am trying to achieve here is depicted in the small program
below.

// Wrapit.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include <map>
#include <list>

using namespace std;

class A
{

private:
string a;
string b;
string c;
public:
A(){}

};

class B
{

private:
string a;
string b;
string c;

public:
B(){cout << "B constructor is being called \n";}
};


class C
{
private:
map<string, A *> aobj;
map<string, B *> bobj;
public:

C(){cout << "Constructor of C called \n";}

template <class T>
T& operator [] (string key)
{
cout << "Operator [] called \n";
return new A(); //if the key has a particular text in it return
new A
// otherwise return new B();
}

};

int _tmain(int argc, _TCHAR* argv[])
{
C c;
c["abcd"] = new A();
c["efgh"] = new B();

return 0;
}


Obviously the above program will give you compiler errors.

I am trying to put a wrapper around the maps. And the insertion to the
maps is done through an
(eg . c["abcd"] = new A()) overloaded [] operator. Further I want to
use just one [] version of the function, but inside I will determine
whether I should return a new A() or a new B(). The string I recieved
as argument will have enough information for me to decide which object
to be returned. How would i do it.

I'm 99.99% sure you can't. Not unless you make both A and B inherit from
a common base-class and return that. You must remember that templates
are compile-time constructs so they can't depend on anything that isn't
known at compiletime.
 
F

Fei Liu

raan said:
What I am trying to achieve here is depicted in the small program
below.

// Wrapit.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include <map>
#include <list>

using namespace std;

class A
{

private:
string a;
string b;
string c;
public:
A(){}

};

class B
{

private:
string a;
string b;
string c;

public:
B(){cout << "B constructor is being called \n";}
};


class C
{
private:
map<string, A *> aobj;
map<string, B *> bobj;
public:

C(){cout << "Constructor of C called \n";}

template <class T>
T& operator [] (string key)
{
cout << "Operator [] called \n";
return new A(); //if the key has a particular text in it return
new A
// otherwise return new B();
}

};

int _tmain(int argc, _TCHAR* argv[])
{
C c;
c["abcd"] = new A();
c["efgh"] = new B();

return 0;
}


Obviously the above program will give you compiler errors.

I am trying to put a wrapper around the maps. And the insertion to the
maps is done through an
(eg . c["abcd"] = new A()) overloaded [] operator. Further I want to
use just one [] version of the function, but inside I will determine
whether I should return a new A() or a new B(). The string I recieved
as argument will have enough information for me to decide which object
to be returned. How would i do it.

My environment: VS2003 on Windows XP.

All your helps appreciated

There are a couple issues with your code:
1) assuming your [] operator works, the return type is a temporary const
T & that cannot be assignee.
2) it's awkward to really tell the compiler to pick up the template
argument, check the following code:


#include <map>
#include <list>
#include <iostream>

using namespace std;

class A
{

private:
string a;
string b;
string c;
public:
A(){}

};

class B
{

private:
string a;
string b;
string c;

public:
B(){cout << "B constructor is being called \n";}
};


class C
{
private:
map<string, A *> aobj;
map<string, B *> bobj;
public:

C(){cout << "Constructor of C called \n";}

template <class T>
T* at (string key)
{
cout << "Operator [] called \n";
return new A(); //if the key has a particular text in it returnnew A
// otherwise return new B();
}
template <class T>
T* operator [] (string key)
{
cout << "Operator [] called \n";
return new A(); //if the key has a particular text in it returnnew A
// otherwise return new B();
}

};
#define _tmain main
#define _TCHAR char

int _tmain(int argc, _TCHAR* argv[])
{
C c;
A* a = c.at<A>("abcd");
A* aa = c.operator[]<A>("abcd");
// c.get<B>["efgh"] = new B();

return 0;
}
 
R

raan

There are a couple issues with your code:
1) assuming your [] operator works, the return type is a temporary const
T & that cannot be assignee.
2) it's awkward to really tell the compiler to pick up the template
argument, check the following code:

I did some rethinking. following is what I really want.

#include "stdafx.h"
#include <map>
#include <list>

using namespace std;

class A
{

private:
string a;
string b;
string c;
public:
A(){}




};

class B
{

private:
string a;
string b;
string c;

public:
B(){cout << "B constructor is being called \n";}
};


class C
{
private:
map<string, A *> aobj;
map<string, B *> bobj;
string cur_key; //store the current key here till a
//valid = operator is called.
public:

C(){cout << "Constructor of C called \n";}

//Get the current key for the map.
string operator [] (string key)
{
cur_key = key;
cout << "Operator [] called " << key.c_str() << endl;
return key;
}

//Insert object A into aobj map with the key stored in cur_key
int operator = (A* a)
{
aobj.insert(make_pair(cur_key, a));
cout << "Operator = A* called \n";
return 1; //Should be an iterator object
}

//insert object B into bobj map with the key stored in cur_key
int operator = (B *b)
{
cout << "Operator = B* called \n";
}


};

int _tmain(int argc, _TCHAR* argv[])
{
C c;
A *a = new A();
c["abcd"] = a;
return 0;
}

As you can see, c["abcd"] will call the [] operator and set the
current key. Then the overloaded assignment operator is called to
insert the object into relevant maps.

The problem is that it won't compile. It gives an error.
error C2679: binary '=' : no operator found which takes a right-hand
operand of type 'A *' (or there is no acceptable conversion)

What is that I am doing wrong here.

~raan
 
V

Victor Bazarov

raan said:
[..store the key and act apon it in operator=..]

What you need is a custom "assigner" object returned from
the operator[]. That object's operator= will actually perform
the insertion.

class C {
...
public:
class MapAssigner {
C& self;
public:
MapAssigner(C& me) : self(me) {}
void operator=(A* pA) {
self.aobj.insert(std::make_pair(self.cur_key, pA));
}
void operator=(B* pB) {
self.bobj.insert(std::make_pair(self.cur_key, pB));
}
};

MapAssigner operator[](std::string const& key) {
cur_key = key;
return MapAssigner(*this);
}
};

Now, where and when you want to do the validation of the 'cur_key'
is up to you.

V
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,994
Messages
2,570,223
Members
46,812
Latest member
GracielaWa

Latest Threads

Top