开发者

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 re开发者_StackOverflow中文版placement, 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?


You can not use non-POD types as fields in union. Use boost::variant or something like it in C++ instead of union. Leave union only for compatibility with modules written in C.


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.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜