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.
精彩评论