heres my variant class:

// *** ADDED BY HEADER FIXUP ***
#include <cstdlib>
#include <iostream>
#include <string>
// *** END ***
#ifndef VARIANT_H_INCLUDED
#define VARIANT_H_INCLUDED

class variant
{
    string a="";
 public:

    variant (string value="")
    {
        a=value;
    }

    variant (double value)
    {
        a=to_string(value);
    }

    friend istream& operator >>(istream &is,variant &obj)
    {
        is>>obj.a;
        return is;
    }

    friend ostream& operator <<(ostream &os,const variant &obj)
    {
        os<<obj.a;
        return os;
    }

    friend istream &getline(istream &in, variant &s1)
    {
        getline(in, s1.a);
        return in;
    }


    variant & operator = (int const & b)
    {
        a=to_string(b);
       return *this;
    }

    variant & operator = (string const & b)
    {
        a=b;
        return *this;
    }

    variant & operator = (double const & b)
    {
        a=to_string(b);
        return *this;
    }

    variant & operator = (float const & b)
    {
        a=to_string(b);
        return *this;
    }

    bool operator == (string const & b)
    {

        return  (a==b);
    }

    operator string() const
    {
        return a; // return string member
    }

    operator double() const
    {
        return atof(a.c_str()) ;
    }

};

#endif // VARIANT_H_INCLUDED

how can i update my class for accept struct's\class's\enum's and others?
why i don't use the template? because i must define the type before use it and then i can't use another type.

Edited 3 Years Ago by cambalinho

windows.h already contains a variant structure (link here). All it is is an union of a lot of objects, and an integer to indicate the type of object that is used.

Here is a simplified version of it, the data members in windows.h do not have the same names as in my code below, but it's the same idea.

struct variant
{
   int vt;
   union
   {
       char*ptr; 
       short sdata;
       unsigned short usdata;
       int idata;
       unsigned int uidata;
       long ldata;
       unsigned long uldata;
       void* unknownptr;
    };
};

Edited 3 Years Ago by Ancient Dragon

Comments
thanks

Below is a simple example. Here is a complete list of vt types. Of course if you create your own class then you can do whatever you want by making up your own type code macros.

#include <windows.h>

void foo(VARIANT* vt)
{
   switch(vt->vt)
   {
        case VT_EMPTY:
        case   VT_NULL:
            break; // nothing to do
        case   VT_I2:
            cout << "Short Integer: " << vt->ival << '\n';
            break;
        case   VT_I4:
            cout << "Long Integer: " << vt->llval << '\n';
            break;
        case   VT_R4: 
            cout << "float: " << vt->fltval << '\n';
            break;
        case   VT_R8:
            cout << "double: " << vt->dblval << '\n';
            break;
   }
 }


 int main()
 {
    VARIANT vt;
    VariantInit(&vt); // initialize the VARIANT
    vt.vt = VT_I4;
    vt.llval = 123;
    foo(&vf);
}

Edited 3 Years Ago by Ancient Dragon

Comments
thanks

so i can do:

class test
    {
      public:
          int a;
    };

 int main()
{
    VARIANT vt;
    VariantInit(&vt); // initialize the VARIANT
    vt.vt = test;
    vt.a = 123; 
}

not tested... but can i do these?

If you want to use a fixed selection of types, then you should use Boost.Variant (discriminated union type, similar to that old C-style variant type in windows.h).

If you want to use any types, then you should use Boost.Any, which is a kind of ultimate type-erasure device.

And if you want to take any type and turn it into a serial stream (like a string), then you should use a serialization scheme, like Boost.Serialization.

These are, generally, three separate problem, so, you have to figure out which one is really the one you want.

Comments
thanks

but can i do these?

Not if you are using the VARIANT from windows.h. If you aren't doing any COM stuff (which you probably are not), then use the types described by Mike, above.

Edited 3 Years Ago by Ancient Dragon

Comments
thanks

i think theres anotherway if you don't mine explain to me:
void *b;
with static_cast, what you can tell me, please?

That's sort of what boost::any does. Although, in practice, using just void* is going to cause some issues, like not being able to invoke the correct destructor before deallocating the memory. Using void* is the traditional C-style way of doing type-erasure, but in C++, it isn't really practical.

In practice, the basic implementation of a class like boost::any is something like this:

class any {
  private:

    struct base {
      virtual const std::type_info& type() const = 0;
      virtual base* clone() const = 0;
      virtual ~base() { };
    };

    template <typename T>
    struct erased : base {
      const std::type_info& type() const {
        return typeid(T);
      };
      base* clone() const {
        return new erased<T>(*this);
      };

      T value;

      erased(const T& val) : value(val) { };
    };

    base* p_b;

  public:

    any() : p_b(NULL) { };

    template <typename T>
    any(const T& val) : p_b(new erased<T>(val)) { };

    ~any() { 
      delete p_b;
    };

    any(const any& rhs) : p_b(rhs.p_b->clone()) { };

    friend void swap(any& lhs, any& rhs) {
      std::swap(lhs.p_b, rhs.p_b);
    };

    any& operator=(any rhs) {
      swap(*this, rhs);
      return *this;
    };

    template <typename T>
    any& operator=(const T& rhs) {
      swap(*this, any(rhs));
      return *this;
    };

    bool empty() const { return (p_b == NULL); };

    const std::type_info & type() const {
      if(p_b)
        return p_b->type();
      else
        return typeid(void);
    };

    template <typename T>
    friend
    T any_cast(const any& rhs) {
      erased<T>* p_e = dynamic_cast< erased<T>* >(p_b);
      if(p_e)
        return p_e->value;
      else
        throw bad_any_cast();
    };

};

This is the basic type-erasure technique used in C++ almost in any places you would typically use void* in C.

do me a favor and see these:

variant (string value)
        {
            a=value;
        }


        variant & operator = (string const &b)
        {
            a=b;
            return *this;
        }

    friend ostream& operator <<(ostream &os,const variant &obj)
    {
        os << obj.a;
        return os;
    }

why the string value isn't saved to 'a'?

Edited 3 Years Ago by cambalinho

You'll have to post how you use that. If the = operator is invoked then line 9 of the code you posted with replace the value set in line 3.

i found the problem... but i don't know fix it :(
the problem can be the class, but using the cout works fine... but see my write function:
if blink is true, instead print the text, print '0000.000'(or even more 0's)

void write()
    {
        setlocale(LC_ALL, "en_US.UTF-8");
        cout <<"";
    }

    template <typename ...B>
    void write(string argHead, B... argTail)
    {
        setlocale(LC_ALL, "en_US.UTF-8");
        if (blnBlink==true)
        {
            CONSOLE_SCREEN_BUFFER_INFO csbi;
            GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &csbi);
            string a;
            a=argHead;
            TextBlink(a, csbi.dwCursorPosition.X, csbi.dwCursorPosition.Y,csbi.wAttributes);
            COORD Position;
            Position.X=csbi.dwCursorPosition.X+strlen(a.c_str());
            Position.Y=csbi.dwCursorPosition.Y;
            SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE),Position);
        }
        else
            cout << argHead;
        write(argTail...);
    }

    template <typename ...B>
    void write(const char *argHead, B... argTail)
    {
        setlocale(LC_ALL, "en_US.UTF-8");
        if (blnBlink==true)
        {
            CONSOLE_SCREEN_BUFFER_INFO csbi;
            GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &csbi);
            string a;
            a=argHead;
            TextBlink(a, csbi.dwCursorPosition.X, csbi.dwCursorPosition.Y,csbi.wAttributes);
            COORD Position;
            Position.X=csbi.dwCursorPosition.X+strlen(a.c_str());
            Position.Y=csbi.dwCursorPosition.Y;
            SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE),Position);
        }
        else
            cout << argHead;
        write(argTail...);
    }

    template <typename A, typename ...B>
    void write(A argHead, B... argTail)
    {
        setlocale(LC_ALL, "en_US.UTF-8");
        if (blnBlink==true)
        {
            CONSOLE_SCREEN_BUFFER_INFO csbi;
            GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &csbi);
            string a;
            a=to_string(argHead);
            TextBlink(a, csbi.dwCursorPosition.X, csbi.dwCursorPosition.Y,csbi.wAttributes);
            COORD Position;
            Position.X=csbi.dwCursorPosition.X+strlen(a.c_str());
            Position.Y=csbi.dwCursorPosition.Y;
            SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE),Position);
        }
        else
            cout << argHead;
        write(argTail...);
    }

but if the blink is false, the text it's printed normaly.
what you can advice me?

This article has been dead for over six months. Start a new discussion instead.