4

I have a situation in my program where I need to do some conversion from strings to various types and obviously the outcome can only be ever one type. So I opted to create a union and called it variant, as such:

union variant
{
    int v_int;
    float v_float;
    double v_double;
    long v_long;
    boost::gregorian::date v_date; // Compiler complains this object has a user-defined ctor and/or non-default ctor. 
}; 

I am using it as follows:

bool Convert(const std::string& str, variant& var)
{
    StringConversion conv;

    if (conv.Convert(str, var.v_int))
        return true;
    else if (conv.Convert(str, var.v_long))
        return true;
    else if (conv.Convert(str, var.v_float))
        return true;
    else if (conv.Convert(str, var.v_double))
        return true;
    else if (conv.Convert(str, var.v_date))
        return true;
    else 
        return false;
}

and then I use that function here:

while (attrib_iterator != v_attributes.end())  //Iterate attributes of an XML Node
            {
                //Go through all attributes & insert into qsevalues map
                Values v;  // Struct with a string & boost::any
                v.key = attrib_iterator->key; 
                ///value needs to be converted to its proper type.
                v.value = attrib_iterator->value;
                variant var;
                bool isConverted = Convert(attrib_iterator->value, var); //convert to a type, not just a string
                nodesmap.insert(std::pair<std::string, Values>(nodename, v));
                attrib_iterator++;
            }

The problem is that if I use a struct then users of it will be able to stick more then one value in it, and that really is not meant to happen. But it seems I cannot use a union either, as I cannot put the boost::gregorian::date object in it. Can anybody advice if there is a way I could use a union?

timrau
  • 22,578
  • 4
  • 51
  • 64
Tony The Lion
  • 61,704
  • 67
  • 242
  • 415

3 Answers3

5

Use boost::variant or boost::any. Union is not a solution when you have to combine non-PODs.

Cătălin Pitiș
  • 14,123
  • 2
  • 39
  • 62
  • @Tony: See this for the explanation/definition of POD's http://stackoverflow.com/questions/4178175/what-are-aggregates-and-pods-and-how-why-are-they-special – Armen Tsirunyan Nov 25 '10 at 12:55
  • +1 for `variant`: compile-time checked, little overhead (similar to union + enum), no need of RTTI... did I mentioned I loved this ? – Matthieu M. Nov 25 '10 at 13:37
1

Instead of a gregorian::date, store a greg_ymd struct, and use the year_month_day() method to convert the date to a ymd.

Martin v. Löwis
  • 124,830
  • 17
  • 198
  • 235
0

Are you saying you can't put the boost::gregorian::date in the union because it's a non-POD type? C++0x relaxes this restriction. If you get gcc 4.6 and build it with -std=c++0x you can put it in a union. See here: http://en.wikipedia.org/wiki/C%2B%2B0x#Unrestricted_unions.

Chris
  • 6,642
  • 7
  • 42
  • 55