Sign in to follow this  

[C++] Getting Pointer Type

This topic is 3300 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 have an Array Data Structure that mimics std::vector. In it, I hold values such as classes and primitive types (ints, floats, etc). I was wonder if there is a was to see if the items in the array are of a certain type. I'm also wondering if there is a way to do this without using typeid(). Any suggestions?

Share this post


Link to post
Share on other sites
You could make a structure that works like a variant.


// this is c++ pseudo code...
typedef enum
{
vNULL = 0
INTEGER = 1,
FLOAT = 2,
DOUBLE = 3
} VariantTypes;

class myVariant : myType(vNULL)
{
VariantTypes myType;

union
{
int myInt;
float myFloat;
double myDouble;
}

public:


bool operator=(const int &a)
{
myType = INTEGER;
myInt = a;
return TRUE;
}

bool operator=(const float &a)
{
myType = FLOAT;
myIFloat = a;
return TRUE;
}

bool operator=(const double &a)
{
myType = DOUBLE;
myIDouble = a;
return TRUE;
}

VariantTypes GetType()
{
return myType;
}
};


The union lets you keep all the elements together, so as to not waste memory.
Whenever you assign a value to the variant, the appropriate overload will be chosen.
It will copy the value, and keep the type.

Variants are great, because you can build arbitrary property sets with them and not worry about typing.

Share this post


Link to post
Share on other sites
Quote:
Original post by Mathucub
You could make a structure that works like a variant.


Hmm, maybe im not explaining this correctly. What I'm making is a serializable array that can serialize anything in it. If the objects it's storing is not derived from CSerializable, then I would want to do a byte dump. Essentially my code looks like this:


if (typeid(val) == typeid(CSerializable))
{
// Call its internal serialize function (overloaded)
buf.write(val.serialize())
}else{
// This means its a primitive (such as int, float, etc)
buf.write(&val, sizeof(val));
}



Or something like that. I would prefer not to use typeid() tho. Your class that you posted is a bit overkill, I think, but i will keep it in mind if all other options are exhausted.

Share this post


Link to post
Share on other sites

if (boost::type_traits::is_pod< val_t >::value)
{
//Do your primitive stuff
} else {
//Do more complicated stuff
}


Where val_t is the type of the value (Which you should know >_>).

Share this post


Link to post
Share on other sites
Quote:

How are you storing the objects in the array?

It's a template.


Quote:
Original post by bobofjoe

if (boost::type_traits::is_pod< val_t >::value)
{
//Do your primitive stuff
} else {
//Do more complicated stuff
}


Where val_t is the type of the value (Which you should know >_>).


Good idea, but what if the Type is an object that doesn't inherit from CSerializable, it will still fail that test and go into the complicated portion of the if statement.

Is it possible to do this using dynamic_cast<> or any type of casting mechanism that can throw an exception if it cannot cast??

ie:

CMyClass val; // not from CSerializable
if (boost::type_traits::is_pod<val>::value)
{...}





Basically, if it's not derived from CSerializable or if its a Primitive, then I will do one thing, else if it is derived from CSerializable, I want it to do something else.

Could you use dynamic_cast<>() or any similar function to check if it can be converted to type CSerializable? Throwing/catching exceptions is fine.

Share this post


Link to post
Share on other sites
Quote:
Original post by RealMarkP
Could you use dynamic_cast<>() or any similar function to check if it can be converted to type CSerializable? Throwing/catching exceptions is fine.


Yes. dynamic_cast<CSerializable&>(val) will throw an exception. It's only a few times more costly than typeid().

Share this post


Link to post
Share on other sites
Quote:
Original post by Bregma
Quote:
Original post by RealMarkP
Could you use dynamic_cast<>() or any similar function to check if it can be converted to type CSerializable? Throwing/catching exceptions is fine.


Yes. dynamic_cast<CSerializable&>(val) will throw an exception. It's only a few times more costly than typeid().


Hmm, how would I go about it throwing an exception?

int *val;
CSerializable *s = dynamic_cast<CSerializable *>(val);

This doesn't compile. (Obviously, I almost never use c++ style casting).

Share this post


Link to post
Share on other sites
Quote:
Original post by RealMarkP]
I have an Array Data Structure that mimics std::vector
Why not use std::vector?

Quote:
Original post by RealMarkP
<code here>
Or something like that. I would prefer not to use typeid() tho.
What's the reasoning for avoiding typeid?


I don't know what type val is, could you just use overloads to take care of the type matching?:

void serialize(CSerializable & s) { /* handle CSerializable */ }

template < typename T >
void serialize(T x) { /* handle non-CSerializable */ }

// elsewhere
MySerializable a;
int b = 0;

serialize(a);
serialize(b);

Share this post


Link to post
Share on other sites
Quote:
Original post by dmatter
Why not use std::vector?

I'd still run into the same problem.

Quote:
What's the reasoning for avoiding typeid?

I just heard it was CPU intensive. No other reasons. I'm experimenting with it right now, so if it works, it works.

Quote:
void serialize(CSerializable & s) { /* handle CSerializable */ }

template < typename T >
void serialize(T x) { /* handle non-CSerializable */ }

// elsewhere
MySerializable a;
int b = 0;

serialize(a);
serialize(b);


The way I designed it is that everything derives from CSerializable, unless its a Primitive type. Therefore I need a way to decern the different type. Surely I can write a function for each time and let the compiler do its magic, but its very repetitive work.

My CSerializable class has a pure virtual function serialize(CByteBuffer &buf), which takes its private members and shoves them into the byte buffer. In the case of my Array class, it's templated so it doesn't know if the items inside of it are derived from CSerializable or not. Therefore it does not know if it should call the serialize() function on the objects it's holding, or somehow manually write the raw bytes into the buffer.

Basically:

// Pseudo code
if (val is of type CSerializable)
{
// Use the serialize funciton of the class that this array stores
val.serialize(byteBuffer); // This writes its private membrs to byteBuffer
}else{
// Object does not contain a serialize function, manually write data
bytebuffer.write(&val, sizeof(val));
}




I hope this explains my problem further.

EDIT: one thing I was trying was dynamic_cast<CSerializable *>((int *) &foo); which gives me a compiler error. Basically what I'm trying to achieve is a runtime error, like an exception or NULL pointer.

Share this post


Link to post
Share on other sites
Maybe something like this might work: (my Visual studio is broke so i haven't checked this at all, i think the principle is sound though, syntax just might be suspect :p )


template <typename T>
class MyObjectHolder
{
template<typename T> friend class Accessor;

public:
Check()
{
if(AccessType.IsSerialisable())
.....
else
.....
}
private:
Accessor<T> AccessType;
}


template <typename T>
class Accessor
{
public:
bool IsSerialisable() {return false;}
}

template <>
class Accessor <CSerialiseable>
{
public:
bool IsSerialisable() {return true;}
}




[Edited by - Guthur on December 5, 2008 4:59:20 PM]

Share this post


Link to post
Share on other sites
Quote:
Original post by rip-off
Is the array homogeneous? If not, how are the items stored?

You can't dynamic_cast primitive types (it requires a primitive type of reflection).


The array is a simple Templated Array, works almost the same as std::vector. For this purpose, assume that my array is an extension of the std:vector class, with an added function that can serialize() it into a buffer of sorts.

Hmm. So if I cannot dynamic_cast against primitive types, the only thing I can really do is either use a variant style class (as mentioned in post #2) or one massive if statement that checks against all known primitive types using the typeid() function:


if (boost::type_traits::is_pod<val>::value)
{
// primitive
}else{
// not a primitive (I pray it was derived from CSerializable)
}



Hmm... Not as ideal as I wanted it.


(I gotta commute home, hope to see what people will come up with)

Share this post


Link to post
Share on other sites
Quote:
Original post by RealMarkP
Quote:
Original post by dmatter
Why not use std::vector?

I'd still run into the same problem.
You would but, that aside, you should always prefer the SC++L containers over your own equivalents unless your profiler tells you otherwise. Statistically I'd be safe in assuming that your vector-like class is buggy and doesn't handle all the corner cases correctly.

Quote:
Quote:
What's the reasoning for avoiding typeid?

I just heard it was CPU intensive. No other reasons.
Only because it performs at run-time as opposed to a statically at compile-time.

Quote:
Quote:
void serialize(CSerializable & s) { /* handle CSerializable */ }

template < typename T >
void serialize(T x) { /* handle non-CSerializable */ }

// elsewhere
MySerializable a;
int b = 0;

serialize(a);
serialize(b);


The way I designed it is that everything derives from CSerializable, unless its a Primitive type. Therefore I need a way to decern the different type. Surely I can write a function for each time and let the compiler do its magic, but its very repetitive work.
Why would you need to write any more than those two overloads? My intention in the example is that MySerializable is some class type derived from CSerializable.

Quote:
In the case of my Array class, it's templated so it doesn't know if the items inside of it are derived from CSerializable or not.
Classically the types stored in array-like collections are homogeneous, it's not clear how you're storing heterogeneous types unless you've used/made something like boost::any.

Share this post


Link to post
Share on other sites
If you are using boost, perhaps you could try boost::is_base_of<CSerializable, T>? I have no idea how it is implemented, but it seems to separate out derivates of CSerializable nicely.

Share this post


Link to post
Share on other sites
This is mixing two completely unrelated problems.
- heterogeneous type container
- serialization

Let's solve serialization first:
template < class T, class Archive >
void serialize(T & value, Archive & a);

template < class Archive > void serialize(int & value, Archive & a);
...
// and so on for all primitive types
template < class Archive > void serialize(CSerializable *, Archive & a);


Next, we need type information
struct Wrapper : public CSerializable {
virtual ~Wrapper() {};
};

template < class T >
struct TypedWrapper : public Wrapper {
TypedWrapper(const T & value) : ptr(new T(value)) {}
// copy and assignment as well, watch copy behavior...
virtual ~Wrapper() { delete ptr; }

// or whatever CSerializable is
virtual void write(MyArchive & a) {
serialize(*ptr, a);
}
virtual void read(MyArchive & a) {
serialize(*ptr, a);
}
private:
T * ptr;
};


Finally, let's put all together:
typedef std::vector<Wrapper *> VariableVector;

template < class T >
void add(VariableVector& v, const T & value) {
v.push_back(new TypedWrapper<T>(value));
};

VariableVector v;
int i = 5;
std::string s = "Hello World";
add(v, i);
add(v, s);

myVector[0]->write(arc);
myVector[1]->write(arc);


Voila. The above works since it encodes the type using templates into virtual functions into each instance inserted into vector.

Oh yea, you're on your own with making this actually work correctly with regard to memory allocation and exception safety.

If life span of VariableVector is short, you might consider using custom allocators to allocate everything in place to avoid trashing heap with 2 dynamic allocations per type inserted.

Serialization overhead is one virtual call per vector entry, serialization itself will be inline expanded inside read/write functions.

The overhead of insertion into array 2 dynamic allocations, one for wrapper, one for copy of instance inserted.

Share this post


Link to post
Share on other sites
Quote:
Original post by visitor
If you are using boost, perhaps you could try boost::is_base_of<CSerializable, T>? I have no idea how it is implemented, but it seems to separate out derivates of CSerializable nicely.


Thank you, Thank you, thank you! This functionality and also similar ones like is_convertable<> also work like a charm!

Also, dmatter, I misunderstood your original post when I read it the first time. I see now what you meant and that also would have worked.

Thanks for the help, everyone!

Share this post


Link to post
Share on other sites

This topic is 3300 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