c++boostoptional-variables

boost::optional<> in a union?


I have an optional POD struct that will be contained inside a union.
boost::optional<> holds its type by value, so I thought this could work:

union helper
{
    int foo;
    struct 
    {
        char basic_info;
        struct details {
            //...
        };

        boost::optional<details> extended_info;
    } bar;
    //  ...
};

helper x = make_bar();

if( x.bar.extended_info )
{
    // use x.bar.extended_info->elements
}

but VS2008 complained that my bar struct now had a copy constructor due to the boost::optional<details> element.

As a replacement, I've added a boolean flag to indicate whether the optional parameter is valid, but it's clunky:

union helper
{
    int foo;
    struct 
    {
        char basic;
        struct details {
            bool valid;
            //...
        } extended;
    } bar;
    //  ...
};

I considered implementing details::operator bool() to return the details::valid variable, but that's obscure and a disservice to humanity.
boost::optional<> clearly documents the syntax and intent and doesn't require detective work.

Finally, the helper union needs to be POD, so I can't do any dynamic allocation - otherwise I would use a pointer.

Any suggestions for something syntactically similar to boost::optional<> that's usable in a union?


Solution

  • As others have mentioned, the ideal thing to do is to change from a union to a boost::variant<>.

    However, if this isn't possible, you can implement a POD approximation of boost::optional<> as follows:

    Implementation

    template <typename T>
    class Optional
    {
        T value;
        bool valid;
    
    public:
    
        // for the if(var) test
        operator bool() const  {  return valid;  }
    
        //  for assigning a value
        Optional<T> &operator=(T rhs)   
        {  
            value = rhs;  
            valid = true;  
            return *this;  
        }
    
        //  for assigning "empty"
        Optional<T> &operator=(void *)  
        {  
            valid = false;  
            return *this;  
        }
    
        // non-const accessors
        T &operator*()   {  return  value;  }
        T *operator->()  {  return &value;  }
    
        // const accessors
        const T &operator*()  const  {  return  value;  }
        const T *operator->() const  {  return &value;  }
    };
    

    The const accessors are necessary if you are holding a const instance of Optional<>.

    Usage

    Like a pointer, Optional<T> has no default state and must be initialized before you can rely on it (null or not).
    Unlike boost::optional<T>, Optional<T> cannot be constructed from its T value type, and can only be constructed from another Optional<T>.
    If you really want to value- or null-initialize it at construction, you could make a helper class with an operator Optional<T>(). I chose not to.

    Construction

    Optional<details> additional_info;
    Optional<details> more_info(additional_info);
    

    Assignment

    // if there's no additional info
    additional_info = 0;
    
    // if there is extended info
    details x;
    //  ...populate x...
    additional_info = x;
    

    Data access

    if( extended_info )
    {
        extended_info->member;
        // - or -
        details &info = *extended_info;
    }
    

    So - it didn't turn out to be too bad. It doesn't make me feel quite warm and fuzzy, but it gets the job done.