Sign in to follow this  

templated subscript operator?

This topic is 4726 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

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<T> converts the string to type T. But this doens't work. I get "../game/Game.cpp:55: error: no match for 'operator[]' in 'Singleton<T>::Instance [with T = Config]()["width"]'" from the compiler when I'm compiling it. In normal templated functions you put <type> 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.

Share this post


Link to post
Share on other sites
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.

Share this post


Link to post
Share on other sites
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.

Share this post


Link to post
Share on other sites
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;
};


Share this post


Link to post
Share on other sites
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"]);

Share this post


Link to post
Share on other sites
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[]<returntype>("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<int>("width"), config.getValue<int>("height"));

Share this post


Link to post
Share on other sites
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.

Share this post


Link to post
Share on other sites
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

Share this post


Link to post
Share on other sites
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.

Share this post


Link to post
Share on other sites
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

Share this post


Link to post
Share on other sites
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.

Share this post


Link to post
Share on other sites

This topic is 4726 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this