1

I'm fairly new to C++, I've been mainly using python. I'm trying to check the type of variable of the value stored in the objects I'm working on. I remember that in Python there was a comand isinstance where I could use it as a condition to run certain commands, like if the next value is a string, do A, and if it's an int do B.

Is there a way to quickly check what's the data type on a variable in C++?

Example:

In python I had an array with a math operation, each character in a field

[3,"+",2]

as I read the array I would separate the ints from the strings with the isinstance command

if isinstance(list[0],int):
        aux1.append(list[0])
        list=list[1:] 
    else:
        if isinstance(lista[0],str):
            aux2.append(list[0
            list=list[1:]

now in C++ I need to do something similar, but this time each character is in a node from a linked list and again, I need to separate them, ints in a linked list, and strings in another linked list

Twhite1195
  • 351
  • 6
  • 17
  • 1
    that doesn't exist in vanilla c++. c++ is a strongly typed language compared to python. – Daniel A. White Mar 07 '16 at 01:28
  • yes, I know C++ is a whole different level, is just that I have a homework and I need to take a different course of action depending on if the variable that I'm evaluating is an int or a string – Twhite1195 Mar 07 '16 at 01:38
  • 2
    I'd also like to add that this is often a "code smell" despite the language (granted there are _some_ legitimate use cases for it) – souldzin Mar 07 '16 at 01:38
  • @Twhite1195 please post an example. – Daniel A. White Mar 07 '16 at 01:38
  • example added to the post – Twhite1195 Mar 07 '16 at 01:51
  • How do you get the data? Like already decriped by other comments, C++ is strongly typed. There is no way to store a value in a varaible without the knowlage whether it is a string or an int. It seems that you did not understand what "strongly typed" means or your question is ambiguous. – JojOatXGME Mar 07 '16 at 03:08
  • 1
    the thing is, I'm getting the operation from a txt file, for example 3+2, then I'm creating a linked list to store that operation,each item on the txt file gets stored as an object, so the list ends up like this: ->3->+->2. Then I gotta split that up, numbers in one list, characters in the other. so I have to check each value as a string, but I still gotta evaluate if the string contains a number or an int so I can separate numbers from characters – Twhite1195 Mar 07 '16 at 04:35
  • 1
    @JojOatXGME what you're describing is "static typing" (which also is what's OP has issues with). "Strong typing" means that values have a single fixed type. This type doesn't need to be known at compile time. An example of such a language (strong but dynamic typing) is lisp. – Daniel Jour Mar 07 '16 at 06:39
  • @DanielJour Thanks. I did not know that there is a differance. About the question, Twhite1195: As far as I understand, you get a string (or single character?) always. You want to check whether it can be interpreted as number. And if it is the case, you want to parse/convert it. I'm right? – JojOatXGME Mar 07 '16 at 12:20
  • Exactly correct, that's where I'm having issues, because the command "stoi(string)" does convert my string into int... Only if its an int, if I try to convert, let's say "h" the whole program crashes – Twhite1195 Mar 07 '16 at 18:36
  • Check https://stackoverflow.com/a/72648097/6219626 – Haseeb Mir Jun 16 '22 at 18:26

2 Answers2

3

What you seem to be struggling with is that C++ is a statically and a (relatively) strongly typed language. For a discussion about what each of these terms actually mean i refer to this other question, as it's explained there probably much better than I could.

First of all you should be sure that you actually need to do things the way you're trying currently. Do not try to write Python style code.

That said, there are basically two different approaches with which you can achieve a behavior that's similar to what Python (dynamically typed, duck typing and thus relatively weak typing) allows you to do:

  1. Use C++'s builtin dynamic type mechanisms. Therefore, you need to create a so called polymorphic base class, that is a class that has at least one virtual member function (the destructor also works if you don't have a defined interface - it most often also must be virtual to avoid nasty issues). A short example:

    struct Value {
      virtual void write_to(std::ostream &) const = 0;
      virtual void read_from(std::istream &) = 0;
      virtual ~Value() {} // Absolutely required!!!
    };
    struct Number : public Value {
      int data;
      void write_to(std::ostream & stream) const {
        stream << "<Number " << data << ">";
      }
      void read_from(std::istream & stream) {
        stream >> data; // Not the same format as write_to, shame on me
      }
      // Implicit destructor is fine
    };
    struct String : public Value {
      std::string data;
      void write_to(std::ostream & stream) const {
        stream << "<String " << data.size() << " " << data << ">";
      }
      void read_from(std::istream & stream) {
        stream >> data; // Not the same format as write_to, shame on me
      }
    };
    

    Using this you can now for example store Values whose actual type you can let the user decide:

    std::vector<std::unique_ptr<Value>> values;
    while (wantsToEnterMoreValues) {
      std::string choice = ask("What type of value do you want to enter?");
      std::unique_ptr<Value> value;
      if (choice == "string") {
        value = std::make_unique<String>();
      } else if (choice == "number") {
        value = std::make_unique<Number>();
      } else {
        // launch apocalypse
      }
      value->read_from(std::cin);
      values.push_back(value);
    }
    

    This is easily extensible to more types. Note that in order to use C++'s builtin dynamic typing you need to go without value semantics, but instead completely use reference semantics, either using real references, or (in most cases where ownership must be transferred, like in above example to the values vector) using pointers.

    The dynamic_cast approach works very similar to this, except that you're using runtime type information more explicitly and don't need a unified interface (but have much more work in order to maintain your code).

  2. Use the union language feature. This only has become really possible with C++11, where union members may be non-trivially construable:

    enum class Type {
      Number, String
    };
    struct Value {
      Type type;
      union {
        std::string string;
        int number;
      };
      Value(std::string const & s) : type(Type::String), string(s) {}
      Value(int n) : type(Type::Number), number(n) {}
      Value(Value const & v) : type(v.type) {
        switch (type) {
          case Type::Number: number = v.number; break;
          case Type::String: new (&string) std::string(v.string); break;
          default: break; // Launch nuclear missiles
        }
      }
      ~Value() {
        switch (type) {
          case Type::String: string.~std::string(); break;
          default: break;
        }
      }
    };
    

    As you can see, this quite a lot of work. With this approach you can use value semantics, but cannot as easily extend your Values to support more types. Moreover, due to using a union, you're going to waste some memory.

Bottom line: You need to implement the behavior on your own, but can do so in exactly the way you want it to behave. For example: You could also implement assignment operators operator=(Value const &) that do implicit type conversions. You can also use the implementations from boost, like boost::any or boost::variant.

I'd like to reference two answers I've written on this site to the very same subject, perhaps they're also helpful for you:

Also some C code which is relevant, because it tries to solve the same issue: https://stackoverflow.com/a/35443434/1116364

Note: All code in this answer is written straight out of memory and not tested. It thus serves only as demonstration of the basic techniques.

Community
  • 1
  • 1
Daniel Jour
  • 15,896
  • 2
  • 36
  • 63
  • +1: for pointing out the _polymorphic base class_, so that I can do further research and learn something new! – John Hany Aug 09 '16 at 08:59
0

Unlike Python, C++ is a strongly typed language. This means that the type of each object is known at compile time.

Having said that, there is a very, very vague analogue that can apply in some circumstances.

If you have a pointer to an object whose class has at least one virtual method, a dynamic_cast will either convert it to a pointer to the requested class, or to a nullptr. This would only work when the most-derived object that's being pointed to includes both classes in its hierarchy, unambiguously.

Sam Varshavchik
  • 114,536
  • 5
  • 94
  • 148
  • " strongly typed language. This means that the type of each object is known at compile time." No. That's static typing what you're describing here. – Daniel Jour Mar 07 '16 at 06:43