Jump to content
  • Advertisement
Sign in to follow this  
Perost

templated subscript operator?

This topic is 5092 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
Advertisement
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
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

GameDev.net is your game development community. Create an account for your GameDev Portfolio and participate in the largest developer community in the games industry.

Sign me up!