Skip to main content
GameDev.net gamedev.net
🔒 Locked

[C++] Creating a multi-type class

Started by d000hg Aug 7, 2009 at 5:04 AM 6 replies 2.1k views
Original Post
d000hg
d000hg
I'm writing a simple scripting type system, and one central part is how values are represented. In this system, the only types used are bool, int, float, string... the issue is because I don't require the scripter to specify value types i the script... e.g if loading a script fragment through XML we might have. I'm considering a Value class which is created from a string, and stores the bool/int/etc values of that string where they can determined, and marks which types the value can be used for. It's also fairly easy to define an order of conversion: bool -> int -> float -> string i.e a value of a type can be treated as any type to the right, but not to the left (int can be read as float, float can't be read as int). This IS a simple system I'm putting together, so probably any value system would be usable. But there's all kinds of choices about how to represent a value, decide on conversions between types, etc. Any thoughts?
_moagstar_
_moagstar_
What language is this?
_moagstar_
_moagstar_
Ah, sorry I didn't see the C++ in the topic title.

I would probably use boost::variant since you know the subset of types that you are going to be working with. I'm not sure if this will fit your needs, but what about something like :

// std#include <string>#include <iostream>// boost#include <boost/mpl/vector.hpp>			#include <boost/mpl/for_each.hpp>#pragma warning(push)#pragma warning(disable:4100) // C4100: unreferenced formal parameter#pragma warning(disable:4512) // C4512: assignment operator could not be generated#include <boost/variant.hpp>#pragma warning(pop)#include <boost/lexical_cast.hpp>#include <boost/assign/std/vector.hpp>#include <boost/foreach.hpp>// in this specific order since this defines also the conversion pathtypedef boost::mpl::vector<bool, int, float, std::string> DataTypes;typedef boost::make_variant_over<DataTypes>::type Value;struct ConvertStringToValue{	ConvertStringToValue(const std::string& stringValue, Value& value) :		m_stringValue(stringValue),		m_value(value),		m_set(false)	{}    template <typename T> 	void operator()(const T& x)    {		if (!m_set)		{			try			{				m_value = boost::lexical_cast<T>(m_stringValue);				m_set = true;			}			catch(boost::bad_lexical_cast&)			{			}		}	}	std::string m_stringValue;	Value&		m_value;	bool		m_set;};struct GetValueTypeString : boost::static_visitor<std::string>{	template <typename T>	std::string operator ()(const T&) const	{		return typeid(T).name();	}	template <>	std::string operator ()(const std::string&) const	{		// typeid gives the full templated name for std::string		return "string";	}};int main(int argc, char* argv[]){    using namespace boost::assign; // bring 'operator+=()' into scope	std::vector<std::string> testValues;	testValues += "1";			// bool	testValues += "-243";		// int	testValues += "4.0";		// float	testValues += "Gezellig!";	// string	BOOST_FOREACH(std::string& testValue, testValues)	{		Value value;		boost::mpl::for_each<DataTypes>(			ConvertStringToValue(testValue, value));		std::cout << boost::apply_visitor(			GetValueTypeString(), value) << ": ";		std::cout << value << "\n";	}		std::system("pause");	return 0;}


You may want to use something else instead of boost::lexical_cast so that for example values like 3.14f get parsed as a float instead of a string, and true/false as bool etc.
rip-off
rip-off
Why not use an existing scripting language like Lua? XML based scripting sounds like an awful idea.
d000hg
d000hg
Quote:
Original post by rip-off
Why not use an existing scripting language like Lua? XML based scripting sounds like an awful idea.
It's a valid question, with a few answers (which you may find valid, or not[wink]):

1. I don't know Lua or have time to learn it right now
2. It's not a scripting language I'm making. It's a rule-based system. XML is used to define the conditions and actions
3. The users of this are not programmers. Letting them loose on writing real code is too much of a support nightmare, when their LUA code is buggy

A bit more on 2. An example might be something like:

<Rule name="Mission Complete">  <Condition>$elapsedTime GT 10</Condition>  <Condition>$distance($player,$goal) LT 12.3</Condition>  <Action>$levelComplete()</Action></Rule><Rule name="Mission Fail">  <Condition>$elapsedTime GT 600</Condition>  <Action>$levelFail()</Action></Rule>
This is rough, but illustrative.
ScottMayo
ScottMayo
Quote:
Original post by d000hg

<Rule name="Mission Complete">  <Condition>$elapsedTime GT 10</Condition>  <Condition>$distance($player,$goal) LT 12.3</Condition>  <Action>$levelComplete()</Action></Rule><Rule name="Mission Fail">  <Condition>$elapsedTime GT 600</Condition>  <Action>$levelFail()</Action></Rule>
This is rough, but illustrative.


This feels like

$levelFail() :: $elapsedTime GT 600
$levelComplete() :: $elapsedTime GT 10 && $distance($player,$goal) LT 12.3
$continue :: true

Where rules get evaluated only if the previous rules fails. In that case, XML, which probably shouldn't be used when the order of peer elements is critical, might not be best.

As for the datatypes... as much as it makes my skin crawl to ever tell anyone to devise a data representation that doesn't come with strict typing information, a single "Value" class with accessors for asInt() and asFloat(), and hints like iCanBeBoolean(), is probably all you need. I find it useful to underdesign things like this, and let the next level's usage dictate what's needed, as I go. (At least, I find that useful when I have the luxury of deferring design.)
Telastyn
Telastyn
A string and a Type seem simple enough. Supply a serializer/de-serializer on the type, then let other stuff deal with how/what to do with the objects.

ScottMayo's option also seems fine; it depends on what you need and what your usage is expected to be.

If you stick with a custom scripting language of course...
d000hg
d000hg
I take it ScottMayo's sample is LUA code? More than likely it could be used, but I think I might take more time to figure how to hook my app's complex data models and functionality as accessible - especially since I already started.

Plus, I am designing this as a proper rules engine, so something more focused might be good... of course down the line adding the ability to support rules in LUA or similar could be cool.

My Value class is pretty similar to ScottMayo's skin-crawling version. Definitely ugly, but functional.

Topic Locked

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

Sign in to reply to this topic.