How to check data type?

Mar 21, 2010 at 4:07pm
I'm writing a simple program which saves all its data to xml file.
I've got a few different classes to save in it, but no idea how to differ them.
I could another string but that won't do in few cases.
Help.
Mar 24, 2010 at 10:03pm
Might typeid(sometype variable) be the function you are looking for?

1
2
3
4
5
6
7
8
9
10
11
12
#include <typeinfo>
#include <iostream>

class someClass { };

int main(int argc, char* argv[]) {
    int a;
    someClass b;
    std::cout<<"a is of type: "<<typeid(a).name()<<std::endl; // Output 'a is of type int'
    std::cout<<"b is of type: "<<typeid(b).name()<<std::endl; // Output 'b is of type someClass'
    return 0;
}


Maybe I just don't understand your question :-/
Mar 24, 2010 at 10:30pm
Yeah, that's exactly what I was looking for, thanks.
Mar 25, 2010 at 12:25pm
Don't use typeid for that. It was reluctantly added to the language and when used, should only be used internally. There is no guarantee that the string returned will be the same across vendors or environments or accross compiler versions ...

If fact, I'd go as far to say that if you're relying on it, you're design is sub-optimal.
Last edited on Mar 25, 2010 at 12:26pm
Mar 25, 2010 at 12:33pm
Polymorphism could be used for this. Consider a virtual method that writes the data to disk.
Mar 25, 2010 at 12:56pm
closed account (1yR4jE8b)
Polymorphism doesn't apply for primitive types, but you could use specialized templates although that could get cumbersome writing a template for every primitive types.

I haven't tested this but in theory, couldn't you check primitive types simply by comparing the type_info returned by the typeid operator?

if (typeid(a) == typeid(int))
//do stuff
Last edited on Mar 25, 2010 at 3:01pm
Mar 25, 2010 at 1:46pm
There is no guarantee that the string returned will be the same across vendors or environments or accross compiler versions ...

Amen. What he said.

Oh, and it doesn't *have* to be unique either.. ;-)

I haven't tested this but in theory, couldn't you check primitive types simply by comparing the type_info returned by the typeid operator?

1
2
if (typeid(a) == typeid(int()))
//do stuff 

That would work, but get ugly quickly. I prefer this one:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
struct Foobar;

template<typename T> struct type_name
{
    static const char* name() { static_assert(false, "You are missing a DECL_TYPE_NAME"); }
};

template<> struct type_name<int> { static const char* name() {return "int";} };
template<> struct type_name<string> { static const char* name() {return "string";} };
template<> struct type_name<Foobar> { static const char* name() {return "Foobar";} };

int main()
{
        cout << type_name<int>::name();  // prints "int"
	cout << type_name<float>::name();  // compile time error. float wasn't declared.
}


Of course, Macros can help to ease the declaration a bit:
1
2
3
4
5
6
#define DECL_TYPE_NAME(x) template<> struct type_name<x> { static const char* name() {return #x;} }

DECL_TYPE_NAME(float);
DECL_TYPE_NAME(string);
DECL_TYPE_NAME(MyClass);
...



Ciao, Imi.
PS: If your compiler doen't have "static_assert" yet, just don't implement name() alltogether. Error message is not that pretty, but you still get compile errors for missing types.
Last edited on Mar 25, 2010 at 1:48pm
Mar 25, 2010 at 2:01pm
if (typeid(a) == typeid(int()))
Really BAD advice.

You should provide a mechanism where each type streams itself into a useable format. One example is the way the iostream library can be used to stream types a textual representation. Do the same for your XML.
Mar 25, 2010 at 2:16pm
I fear our OP ran away with typeid().name under his arm... *sigh*. ;-)

Ciao, Imi.
Mar 25, 2010 at 2:22pm
That's fine.

It'll work until he has to port his code and then he'll find all his type field is wrong and will have to recode all his data or hack is program.
Mar 25, 2010 at 2:57pm
closed account (1yR4jE8b)
if (typeid(a) == typeid(int))
Really BAD advice.

You should provide a mechanism where each type streams itself into a useable format. One example is the way the iostream library can be used to stream types a textual representation. Do the same for your XML.


Forgive my ignorance, but why is it bad advice?
Last edited on Mar 25, 2010 at 3:01pm
Mar 25, 2010 at 3:06pm
Mar 25, 2010 at 3:45pm
Forgive my ignorance, but why is it bad advice?


Using typeid() itself is safe in in comparing it to other typeid's during the same programm execution. It's the .name() where there is no guarantee about at all.

But even for typeid, you should not store it in some file. Just think of it as some type identifier that changes every time you run your code. ;-)


The most place where typeid is used is in such if-comparison to check for the dynamic type of a base class:
1
2
3
4
5
6
7
void f (myclass* p)
{
     // do we really have a myclass? Maybe I got a subclass of myclass?
     // I really want to have myclass here, so lets check:
     if (typeid(*p) == typeid(myclass))
         ...
}


However, this code has most probably serious design problems. Most of the time you just should not have to care whether you got myclass* or a subclass of it. That's what inheritance is about, isn't it?

The same goes for integral types along a similar line of reasoning. typeid(int) != typeid(long), but most code should just not care whether he got a long when he wanted an int - as all you can do with ints you can also do with longs.. roughly said..

Ciao, Imi.
Last edited on Mar 25, 2010 at 3:47pm
Mar 25, 2010 at 4:15pm
I fear our OP ran away with typeid().name under his arm... *sigh*. ;-)

He did not, still here.
Well, after reading everything I think I'll stay with typeid(), it will be just fine.
Thanks for your effort.
Mar 25, 2010 at 5:02pm
The example above built on a Microsoft compiler:
a is of type: int
b is of type: class someClass

The example above built on gcc on Windows:
a is of type: i
b is of type: 9someClass
Mar 25, 2010 at 5:17pm
Still fine, knowing this I can make something to prevent such behaviour. Thanks again
Topic archived. No new replies allowed.