0

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 by cambalinho

3
Contributors
12
Replies
34
Views
3 Years
Discussion Span
Last Post by cambalinho
Featured Replies
  • windows.h already contains a variant structure ([link here](http://msdn.microsoft.com/en-us/library/windows/desktop/ms221627(v=vs.85).aspx)). 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 … Read More

  • Below is a simple example. [Here](http://msdn.microsoft.com/en-us/library/cc237865.aspx) 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; // … Read More

  • If you want to use a fixed selection of types, then you should use [Boost.Variant](http://www.boost.org/doc/libs/1_55_0/doc/html/variant.html) (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](http://www.boost.org/doc/libs/1_55_0/doc/html/any.html), which is a kind of ultimate type-erasure device. And if you … Read More

  • > 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. Read More

1

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 by Ancient Dragon

Votes + Comments
thanks
1

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 by Ancient Dragon

Votes + Comments
thanks
0

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?

1

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.

Votes + Comments
thanks
1

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 by Ancient Dragon

Votes + Comments
thanks
0

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

0

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.

0

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 by cambalinho

0

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.

0

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 topic has been dead for over six months. Start a new discussion instead.
Have something to contribute to this discussion? Please be thoughtful, detailed and courteous, and be sure to adhere to our posting rules.