views:

785

answers:

9

Hello, I have a small question: how do I find out what type a C++ pointer is?

I often use a small function in my console programs to gather input, which looks something like this:

void query(string what-to-ask, [insert datatype here] * input)

I would like to create a generic form, using a void pointer, but I can't cin a void pointer, so how to I find out it's type so I can cast it?

+7  A: 

It's been a long time since the last time I coded in C++, but...

Can't you use a Template?

Bruno Reis
The OP is looking for RTTI, and that doesn't apply to void*. Template is the answer.
Tanktalus
A: 

If I understand what you're asking then the usual way to do this is to create an interface class that supports query(string what-to-ask) and then instead of using a void pointer just pass a pointer to the interface. Then you can call query() on that instance.

Aaron
+6  A: 

You can't.

However, one alternative is to do away with void pointers, make everything derive from a common base class and use RTTI.

An example:

class Base
{
public:
   virtual ~Base() {}
};

class Foo : public Base { /* ... */ };

void SomeFunction(Base *obj)
{
    Foo *p = dynamic_cast<Foo*>(obj);
    if (p)
    {
        // This is of type Foo, do something with it...
    }
}
asveikau
should be `dynamic_cast<Foo*>`
Georg Fritzsche
yeah, that's what I meant. :-) fixed.
asveikau
Be aware that dynamic_cast can be very slow - easily a microsecond apiece, for any class hierarchies larger than trivial.
Crashworks
A: 

Nope. You can't do this. If you need something like this, I suggest Boost.Any.

rlbond
+1  A: 

void* is the form all data have. You can't "determine" it -- it is it, any data you have in program are void*! Yes, they are raw chunks of memory, by design.

You could program whole your code with use of void* only. Luckily, C language provides additional convenience to you, letting you manipulate some data as is they were not void*. But if you're going to use this convenience, you should not cast them to void* and forget about what type they were.

Pavel Shved
All POINTERS are void*. Last time I checked, a char is not void*. An int might not be void*. A float is not void*. But char*, int* and float* are.
luiscubal
His point is that all data is nothing but bytes in memory. Ints, chars, strings, etc. are just interpretations.
Charles Salvia
+2  A: 

Your question is not at all clear to me, but perhaps what you want is to overload query

void query(string what2ask, int* input) {
   cout << what2ask;
   cin >> *input;
}


void query(string what2ask, float* input) {
   cout << what2ask;
   cin >> *input;
}

int age;
float sqrt2;
query("How old are you?", &age);
query("What's the square root of 2?", &sqrt2);
Grumdrig
Brad
A: 

If you control the datatype yourself, I would probably make a class/struct that contains an enum of all of the data types you care about and pass that. You could then query the passed in pointer for it's datatype, and then cast appropriately.

IE ( pseudo code warning - treating this as a struct for now. )

class MyDataType {
     enum aDataType type;
     void * myData;
}

void query( string whatToAsk, MyDataType * pdata)
{
    switch ( pdata.type) {
        case integer:
              int * workInt = (int * )  pdata;
              do whatever you want to to get the data
              break;
        case someFunkyObject:
              someFunkyObject pob = (SomeFunkyObject *) pdata;
              Do whatever you want with the data.

        etc.
    }
}
John Chenault
If I were tagging with enums (rather than using RTTI), I would be more inclined to make "myData" a union instead of a void *... Fewer pointers that way, and no double-indirection. Although it's much more C style than C++.
asveikau
A: 

You could read it in as a char * and then parse the string (char by char) to determine if it is an int, float, string, whatever. The tricky part is converting it.

For example:

for each character in string

if (character is a '.')

++decimalcount

else if (character is a letter)

++lettercount

end for loop

if decimalcount > 0 && lettercount == 0 parse through each digit from right to left, multiplying by powers of 10 and adding the sum

else if decimalcount == 1 && lettercount == 0

learn how floats are represented in binary and find someone else's function to convert it for you

else if lettercount > 0

it's a string. yay!

Rantaak
+2  A: 

Instead of passing a void* around that you then need to cast to the correct type you should probably use a template function that can be used with all types you want to read.

This way you get type-safe code and don't have to way to write special code for most input types:

template<typename T>
void query(const string &whattoask, T &input) {
  cout << whattoask << endl;
  cin >> input;
  cout << endl;
}

int main() {
  int i;
  double d;
  string s;

  query("An integer: ", i);
  query("Floating point: ", d);
  query("A word: ", s);
}
sth
Alright! 2 for template, and that's what I'm going with. Thanks!
new123456