Skip to main content
gamedev.net
🔒 Locked

templated subscript operator?

Started by Perost Jan 1, 2005 at 11:43 AM 10 replies 1.9k views
Original Post
Perost
Perost
I'm writing a config class for my game, and you can use the subscript operator to retrive values, like:
int width = config["width"];
But since it returns strings this doesn't work. I thought that I'd overload the subscript operator so that it returns any type with the help of templates. I wrote this function:

template<class T> const T& Config::operator[] (const string &name)
{
	if(mReader[name].empty())
	{
		return StringTo<T>(mDefaults[name]);
	}
	return StringTo<T>(mReader[name]);
}
This function checks whether a value has been read from file, otherwise it returns a default value. StringTo converts the string to type T. But this doens't work. I get "../game/Game.cpp:55: error: no match for 'operator[]' in 'Singleton::Instance [with T = Config]()["width"]'" from the compiler when I'm compiling it. In normal templated functions you put after the function name when calling it, but where to put it in this case? I've searched like a madman after a solution, but I can't find anything [crying]. If anyone know the answer to this, then I'd really appreciate some help.
hplus0603
hplus0603
The typical solution for this is to store values in a variant type, and return the variant type. If you want automatic conversion, then provide type conversion operators on the variant type. The biggest design question is what you should do when you ask for, say, an int, but the stored value is the string "christmas pudding". Return a default? Throw an exception? Crash?

If you don't know what a variant type is, it's basically a smart union. You can probably google for it.
enum Bool { True, False, FileNotFound };
Perost
Perost
Ok, I'll check that out.
Perost
Perost
Sorry, I can't really find anything useful on variant types. But I've experimented a bit with unions, and it seems like you can't use strings in them. Or am I wrong? If that it the case, then variants won't work, since I need strings. But back to my first question. Is there no way to make my function work as it is? Because if I'd change it to a normal function it would work. I could use something like this:
int width = config.get("width");

Of course you'd have to check that the stored value is valid.

blizzard999
blizzard999
Or you can add several functions

bool Read(int&   value, const char* string);bool Read(float& value, const char* string);...//and for the other 'types'bool Read(StringReadable& value, const char* string);


where StringReadable is an abstract base class that supports a function like

class StringReadable{public:   virtual void FromString(const char* string) = 0;};
Perost
Perost
Yes, I could do that. But what I need is a function that returns any type, so that I can use it in functions. I should propably have said this before, but I want to use it like:
SetVideo(config["width"], config["height"]);

Deyja
Deyja
Operator[] won't work because you'd have to call it explicitly, which makes it kind of pointless. Calling it would have to look like config.operator[]("string"), because theres no other way to supply that template parameter. You can do it with a normal function. It will look like this:

SetVideo(config.getValue("width"), config.getValue("height"));
Perost
Perost
Thanks Deyja! That's what I wanted to know. I already knew about how to get it to work with normal functions like you showed, but not how to use the [] operator. And yes, it does indeed seem pointless to use it, so I might go with a normal function.
Neophyte
Neophyte
Another thing you *can* do (I'm not necessarily recommending this) is to have your operator[] return a type of your creation with conversion operators defined for primitive types.
For instance:
class Value {public:  Value() { }  Value ( const string& s ) : m_value(s) { }  operator int() const {    return StringTo<int> ( m_value );  }  operator double() const {    return StringTo<double> ( m_value );  }  operator string() const {    return m_value;  }  // Etc...private:  string m_value;};int main() {  Value value ( "42" );  int i = value;  cout << i << endl;  return 0;}



On a related topic: Is it possible to create an implicit conversion from one type to another without making a new member function in one of the types?

- Neophyte
Fruny
Fruny
Quote:
Original post by Neophyte
On a related topic: Is it possible to create an implicit conversion from one type to another without making a new member function in one of the types?


Not as far as I know.
"Debugging is twice as hard as writing the code in the first place. Therefore, if you write the code as cleverly as possible, you are, by definition, not smart enough to debug it." — Brian W. Kernighan
Zahlman
Zahlman
Following up on what Deyja said: the template could (if I'm not smoking anything) also be disambiguated by assigning to a temporary, like this:

int w = config["width"];int h = config["height"];SetVideo(w, h);


Or you could (again, unless I'm smoking something) make the operator[] take a second dummy parameter of the required type, like this:

template<class T> const T& Config::operator[] (const string &name, T dummy) {  std::string result = mReader[name];  if(result.empty()) return StringTo<T>(mDefaults[name]);  return StringTo<T>(result);}// The "int(0)"s here should provide anonymous, auto storage ints.// But I'm not sure you can really do that...SetVideo(config["width", int(0)], config["height", int(0)]);


Or you could cause the Config class to maintain the association between key names and types... although I can't think of a way to do that without RTTI :s
Perost
Perost
Zahlman, I don't think that you first suggestion works at all. If I try something like that, I only get that there is no such function. That is, you need to use syntax that Deyja showed. However, I think that your second suggestion would work. I've actually been thinking about it myself, but that would actually make it longer. But thanks for the suggestions.

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.