Templated Storage

Another user (NGen) recently asked a question here about how to implement a templated class such that it could have generic get/set methods that could get/set a value of a type specified by the template parameter. While thinking about this, I thought - can this be taken a step further such that the class need not itself be templated?

I came up with the following solution, but the only way I could pull it off is with a somewhat ikky hack to uniquely identify each object (_id/s_id in the below). Is there a better way to pull this off? As it's implemented below, each Storage object can store at most 1 object of each type, but this could be extended such that it could store a list, map, etc of objects.

Storage.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
#include <iostream>
#include <map>
#include <string>

using std::cout;
using std::endl;
using std::map;
using std::string;

class Storage
{
public:
	Storage()
	{
		_id = ++s_id;
	}	
	
	template <class T>
	void set(T val_)
	{
		T * pT = _get<T>();
		*pT = val_;
	}
	
	template <class T>
	T get() const
	{
		T * pT = _get<T>();
		return *pT;
	}
	
private:
	template <class T>
	T * _get() const
	{
		static std::map<unsigned int, T> mapT;
		if (mapT.find(_id) == mapT.end())
		{
			// Throw?
		}
		return &mapT[_id];
	}
	
	unsigned int _id;
	static unsigned int s_id;
};

unsigned int Storage::s_id = 0;


main.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
int main()
{
	Storage s;
	s.set(5);
	s.set<std::string>("hello world!");
	
	Storage s2;
	s2.set(10);
	s2.set<std::string>("hello universe!");
	
	cout << "int = " << s.get<int>() << endl;
	cout << "std::string = " << s.get<std::string>() << endl;
	cout << "int = " << s2.get<int>() << endl;
	cout << "std::string = " << s2.get<std::string>() << endl;	

	return 0;
}


Thoughts?

--Rollie
I think you just reinvented boost::any, or at least its concept. Your implementation is far less efficient.

There's no harm reinventing the wheel if you don't look at the blue prints while you do it. Even though it's less efficient he could of come up with something innovative in the process. Some one could use his code as a jumping point for their own implementation.

as a note, I had the same idea (kinda sorta) my class was to be used in the scripting language I've been developing for my homebrew console.

He're the code, well...some of it, I can't find the most recent version of it.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
//---------------------------------------------------------	
/**
	Var Class used for creating a variable in bi0script
	contains an anonymous union with common types,
	an enumeration for distiguishing those types, as well as
	an integer for storing type ID
**/
//---------------------------------------------------------	
	class var{
	private:
		union{
			int      i;
			float    f;
			double   d;
			char     c;
			zString  z;
			long     l;
			bool	 b;
		};
		enum{
			INT = 0,
			FLOAT,
			DOUBLE,
			CHAR,
			ZSTRING,
			LONG,
			BOOL
		};
		int Type;
	public:
		template<typename t> int get_Type(t input);
		template<typename t> t operator=(t assignment);
		template<typename t> bool operator==(t assignment);

	};
	//---------------------------------------------------------
	template<typename t> bool var::operator==(t assignment){
		Type = get_Type(assignment);
		switch(Type){
		case INT:
			if(i == assignment)
				return true;
			break;
		case FLOAT:
			if(f == assignment)
				return true;
			break;
		case DOUBLE:
			if(d == assignment)
				return true;
			break;
		case CHAR:
			if(c == assignment)
				return true;
			break;
		case ZSTRING:
			if(z == assignment)
				return true;
			break;
		case LONG:
			if(l == assignment)
				return true;
			break;
		case BOOL:
			if(b == assignment)
				return true;
			break;
		}
		return false;
	}
	//---------------------------------------------------------	
	template<typename t> int var::get_Type(t input){
		if(typeid(t) == typeid(i))
			return INT;
		if(typeid(t) == typeid(f))
			return FLOAT;
		if(typeid(t) == typeid(d))
			return DOUBLE;
		if(typeid(t) == typeid(c))
			return CHAR;
		if(typeid(t) == typeid(z))
			return ZSTRING;
		if(typeid(t) == typeid(l))
			return LONG;
		if(typeid(t) == typeid(b))
			return BOOL;
	}
	//---------------------------------------------------------
	template<typename t> t var::operator=(t assignment){
		Type = get_Type(assignment);
		switch(Type){
		case INT:
			i = assignment;
			break;
		case FLOAT:
			f = assignment;
			break;
		case DOUBLE:
			d = assignment;
			break;
		case CHAR:
			c = assignment;
			break;
		case ZSTRING:
			z = assignment
			break;
		case LONG:
			l = assignment;
			break;
		case BOOL:
			b = assignment;
			break;
		}
	}



Topic archived. No new replies allowed.