Alex Walker Alex Walker - 2 months ago 10
C++ Question

Issues with trying to create a generic data type with classes C++

I am having an issue with my C++ program. Right now I am just trying to create a generic "variable" utilizing operator overloading. So the issues is when I determine
the type of data passed. (I must do this because I am later overloading the << operator so that ostream can output the correct data) The conditional statement
does not work as expected. Here is the code

#include <iostream>
#include <vector>
#include <istream>
#include <ostream>

class SLVar
{
public:
friend std::ostream& operator<<(std::ostream& os, const SLVar& var);
const char* str;
char ch;
int in;
float fl;
double dl;
const char* type; //Later initialized
template <typename T>
T operator=(T var)
{
if (typeid(T).name() == typeid(int).name())
{
type = "int"; in = var;
}
else if (typeid(T).name() == typeid(const char*).name())
{
type = "string"; str = var;
}
else if (typeid(T).name() == typeid(float).name())
{
type = "float"; fl = var;
}
else if (typeid(T).name() == typeid(double).name())
{
type = "double"; fl = var;
}
else if (typeid(T).name() == typeid(char).name())
{
type = "char"; ch = var;
}
}
};
std::ostream& operator<<(std::ostream& os, SLVar& var)
{
if (var.type == "string")
{
os << var.str;
}
else if (var.type == "int")
{
os << var.in;
}
else if (var.type == "float")
{
os << var.fl;
}
else if (var.type == "double")
{
os << var.dl
}
else if (var.type == "char")
{
os << var.ch;
}
return os;
}
int main()
{
SLVar var;
var = 5;
std::cout << var << std::endl;
return 0;
}


That should be the final code once that class is done. But the error persists when I try to set var = blah. It gives cannot convert const char* to int or
cannot convert char to int or anything of the sort. It was my impression that that code does not matter at all if it is not true. If I comment out the part
where I set the correct variables it runs with no issue

#include <iostream>
#include <vector>
#include <istream>
#include <ostream>

class SLVar
{
public:
friend std::ostream& operator<<(std::ostream& os, const SLVar& var);
const char* str;
char ch;
int in;
float fl;
double dl;
const char* type; //Later initialized
template <typename T>
T operator=(T var)
{
if (typeid(T).name() == typeid(int).name())
{
type = "int"; //in = var;
}
else if (typeid(T).name() == typeid(const char*).name())
{
type = "string"; //str = var;
}
else if (typeid(T).name() == typeid(float).name())
{
type = "float"; //fl = var;
}
else if (typeid(T).name() == typeid(double).name())
{
type = "double"; //fl = var;
}
else if (typeid(T).name() == typeid(char).name())
{
type = "char"; //ch = var;
}
}
};
std::ostream& operator<<(std::ostream& os, SLVar& var)
{
if (var.type == "string")
{
os << var.str;
}
else if (var.type == "int")
{
os << var.in;
}
else if (var.type == "float")
{
os << var.fl;
}
else if (var.type == "double")
{
os << var.dl;
}
else if (var.type == "char")
{
os << var.ch;
}
return os;
}
int main()
{
SLVar var;
var = "Hello world";
std::cout << var << std::endl;
return 0;
}


This runs, but only when I comment var = blah as shown above. So how can I fix this? Again it was my understanding that if the if statement is not true
the code inside wont even run. But it seem to anyway. I do not understand why this is happening. Can someone shed some light on it? Basically all I want to
do is create a "generic data type" and use the operator=() to set it.

Answer

I understand the need is to be able to declare:

SLVar var;

and later decide to assign integer, string, float, whatever without the need of fixing the type by a template (kind of dynamic typing)

I'm proposing a solution with a lot of compromises, without typeinfo at all and without templates (the template is useless here since you have to perform a type check within the function)

either, I kept only const char * and int types for simplicity's sake but that can be easily extended.

When assigning, the type is set in an enumerate, later used by the console write function.

#include <iostream>
#include <vector>
#include <istream>
#include <ostream>

class SLVar
{
    private:
        const char* str;
        int in;
        enum TheType { TYPE_INT, TYPE_CHARPTR, TYPE_UNKNOWN };
        TheType type=TYPE_UNKNOWN;

    public:
        friend std::ostream& operator<<(std::ostream& os, const SLVar& var);

        SLVar & operator=(int var)
        {
            in = var;
            type=TYPE_INT;
            return *this;
        }
        SLVar &operator=(const char *var)
        {
            str = var;
            type=TYPE_CHARPTR;
            return *this;
        }

};
std::ostream& operator<<(std::ostream& os, const SLVar& var)
{
    switch (var.type)
    {
    case SLVar::TYPE_CHARPTR:
        return os << var.str;            
    case SLVar::TYPE_INT:
        return os << var.in;           
    default:
      return os;  // not printing anything
      }       
}
int main()
{
    SLVar var;
    var = "Hello world";
    std::cout << var << std::endl;    
    var = 35;    // kind of dynamic typing through assignment
    std::cout << var << std::endl;

}

result:

Hello world
35

It's still missing a lot of things, like default constructor, copy constructor... but the principle works.