Jump to content
  • Advertisement
Sign in to follow this  
pauls_1979

C++ Template Random Access Operator

This topic is 3768 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 am in the process of creating a generic data class, to help me simplify the parsing of object attributes from text/xml documents. This class will be string based and I will need to be able to cast it to/from pretty much any basic type i.e. char *, bool, int and float. Here's a rough first pass:
class CGeneric
{
	public:
		
		CGeneric(const char *pString)
		{
			strncpy(m_string, pString, sizeof(m_string) - 1);
		}

		operator const char * () const
		{
			return((const char *)m_string);
		}

		operator int () const
		{
			return((int)atoi(m_string));
		}

		operator float () const
		{
			return((float)atof(m_string));
		}

		void operator = (const char *pString)
		{
			strncpy(m_string, pString, sizeof(m_string) - 1);
		}

		void operator = (int value)
		{
			sprintf(m_string, "%d", value);
		}

		void operator = (float value)
		{
			sprintf(m_string, "%f", value);
		}

	private:

		char	m_string[32];
};

void TestFunction()
{
	CGeneric	genericData("12.4");

	int	myInt = genericData;	// myInt = 12

	float	myFloat = genericData;	// myFloat = 12.4
}







This works pretty nicely, but I would really like to add array/random access functionality, which would work something like this:
struct CVector3
{
	float	x, y, z;
};

void TestFunction()
{
	CGeneric	genericData("10, 15, -12");

	CVector3	pos;

	pos.x	= genericData<float>[0];
	pos.y	= genericData<float>[1];
	pos.z	= genericData<float>[2];
}







Unfortunately I'm having trouble implementing the operator. It isn't possible to create separate functions for each type (I get a compile error because the functions differ only by return type), so the only other way I can see to do this is to declare a template function like this:
template <typename TYPE> TYPE operator [] (int i)
{
	return((TYPE)0); // Worry about implementation details later.
}







This compiles, but I do not know how I can then tell the compiler what type I want to access. I tried genericData<int>[0], <int>genericData[0] and genericData[0]<int>, but all produced compile errors. Have I hit a dead end or is there a way to specify the type? If I have hit a dead end, does anyone have any suggestions? Thanks in advance.

Share this post


Link to post
Share on other sites
Advertisement
Why not have two classes, the first class (CGenerics?) contains a vector of CGeneric classes. This class also splits up the comma-based input to each CGeneric instance in its constructor. The [] operator then returns a CGeneric class reference, which uses the type conversion operators you already have.

Also, I feel like I should point out that making m_string a fixed size isn't very nice. What's wrong with std::string, and std::stringstream for the conversions? atoi and sprintf aren't very C++ either. atoi isn't even standard C or C++ I believe. strtol, etc. is.

Share this post


Link to post
Share on other sites
Quote:
Why not have two classes, the first class (CGenerics?) contains a vector of CGeneric classes. This class also splits up the comma-based input to each CGeneric instance in its constructor. The [] operator then returns a CGeneric class reference, which uses the type conversion operators you already have.


Thanks, I have considered this, but I would ideally like to keep it to a single generic object. I have a system for binding attributes, and want to be able to pass a single parameter when setting an object attribute, without caring whether it's a list or not. Then I can let the object worry about the finer details. Of course if I can't find another solution, then yours may be the best approach.

Quote:
Also, I feel like I should point out that making m_string a fixed size isn't very nice. What's wrong with std::string, and std::stringstream for the conversions? atoi and sprintf aren't very C++ either. atoi isn't even standard C or C++ I believe. strtol, etc. is.


Don't worry, I'm well aware of these issues and I plan to fix them once the design is complete. I just wanted to get something up and running first.

Share this post


Link to post
Share on other sites
Use this:

CGeneric operator[](const unsigned int index) const
{
unsigned int c = 0;
unsigned int i;
for (i = 0; m_string; ++ i){
if (c == index)
return CGeneric(&m_string);
if (m_string == ',')
++ c;
}
return CGeneric("");
}



This does conflict with your operator:

operator const char * () const
{
return((const char *)m_string);
}



But IMO I'd get rid of the char* for string and replace them with std::string's. That will solve it.

Share this post


Link to post
Share on other sites
Thanks guys, I had a brain wave just after reading Mike nl's reply, and yeah, it's pretty much the same as the solution proposed by eq. Seems pretty obvious in hindsight, and works nicely, thanks again.

Share this post


Link to post
Share on other sites
EDIT:

second thought, just do something like this:


#include <iostream>
#include <vector>
#include <sstream>
#include <string>

using namespace std;

class CGeneric
{
public:

explicit CGeneric(const string& str) : str_(str) { }

template <typename Type>
operator Type () const
{
Type var;
istringstream iss(str_);
iss >> var;

if(!iss.bad() && !iss.fail()) { /* throw exception*/ }

return var;
}

template <typename Type>
CGeneric& operator = (const Type& var)
{
ostringstream oss;
oss << var;
str_ = oss.str();

return *this;
}

private:

string str_;
};

struct CVector3
{
float x, y, z;
};

istream& operator >> (istream& is, CVector3& vec)
{
static string ignore_comma;
return is >> vec.x >> ignore_comma >> vec.y >> ignore_comma >> vec.z;
}

ostream& operator << (ostream& os, const CVector3& vec)
{
return os << vec.x << ", " << vec.y << ", " << vec.z;
}

void main(int argc, char** argv)
{
CGeneric genericData("12.4");

int myInt = genericData; // myInt = 12

genericData = "2";

float myFloat = genericData; // myFloat = 2

cout << myInt << ' ' << myFloat << endl;

genericData = "12, 12, 12";

CVector3 foo = genericData;

cout << foo << endl;

cin.get();
}



useful links:
http://www.gotw.ca/publications/mill19.htm
http://www.boost.org/doc/libs/1_35_0/libs/conversion/lexical_cast.htm



[Edited by - godecho on June 27, 2008 8:41:25 AM]

Share this post


Link to post
Share on other sites
Quote:
Original post by pauls_1979
I am in the process of creating a generic data class, to help me simplify the parsing of object attributes from text/xml documents.


What is wrong with established canonical representation of XML DOM?

You have Node and Attributes, each of which is a sequence. Elements of the sequence are simple values.

Vector in XML looks like this:
<vector x="1" y="2" z="3"/>
or
<vector>
<x>1</x>
<y>2</y>
<z>3</z>
</vector>
or
<vector>
<coord name="x" value="1"/>
<coord name="y" value="2"/>
<coord name="z" value="3"/>
</vector>
or perhaps some other variation


The above format is adequate and suitable for representation of arbitrary data type.

XML has its uses, but unfortunately it gets often abused, throwing away the benefits, and just keeping cumbersome syntax.

XML is a good choice when you will be dealing with a lot of context-free transformations. It is absolutely wrong choice for compact representation of data, since XML is by definition verbose.


The canonical entity serialization for arbitrary classes looks something like this:
// First of the above formats
struct Foo {
Foo(const xml::dom::Node & node) {
x = node.getAttribute("x").as<double>();
y = node.getAttribute("y").as<double>();
y = node.getAttribute("z").as<double>();
}
};

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.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!