Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is there a dummy union member in some implementations of std::optional?

Both libstdc++ (GNU) and libc++ (LLVM) implement std::optional value storage using a union and both of them include a dummy member.

GNU implementation:

using _Stored_type = remove_const_t<_Tp>;
struct _Empty_byte { };
union {
    _Empty_byte _M_empty;
    _Stored_type _M_payload;
};

LLVM implementation:

union
{
    char __null_state_;
    value_type __val_;
};

My question is: Why do we need these _M_empty/__null_state_ members? Is there something wrong with a single-member union?

like image 551
r3mus n0x Avatar asked Aug 14 '19 14:08

r3mus n0x


People also ask

What is the use of std :: optional?

The class template std::optional manages an optional contained value, i.e. a value that may or may not be present. A common use case for optional is the return value of a function that may fail.

Can Union have member functions C++?

A union can have member functions (including constructors and destructors), but not virtual (10.3) functions. A union shall not have base classes.


1 Answers

Single member union creates all sorts of problem when trying to be default constructible and be constexpr compatible.

Consider this code:

struct nontrivial {
    constexpr nontrivial(int o) : u{o} {}
    int u;
};

union storage {
    nontrivial nt;
};

struct optional {
    storage s;
};

constexpr auto run() -> int {
    optional o;
    return o.s.nt.u;
}

int main() {
    constexpr int t = run();
}

This is ill formed because optional has a deleted constructor.

Then a simple fix would be to add a constructor that initialize no union member:

union storage {
    constexpr storage() {} // standard says no
    nontrivial nt;
};

But it won't work. Constexpr unions must have at least one active member. It cannot be an empty union. To workaround this limitation, a dummy member is added. This makes std::optional useable in constexpr context.

(Thanks @Barry!) From [dcl.constexpr]/4 (emphasis mine):

The definition of a constexpr constructor whose function-body is not = delete shall additionally satisfy the following requirements:

  • if the class is a union having variant members ([class.union]), exactly one of them shall be initialized;

  • if the class is a union-like class, but is not a union, for each of its anonymous union members having variant members, exactly one of them shall be initialized;

  • for a non-delegating constructor, every constructor selected to initialize non-static data members and base class subobjects shall be a constexpr constructor;

  • for a delegating constructor, the target constructor shall be a constexpr constructor.

like image 73
Guillaume Racicot Avatar answered Oct 13 '22 17:10

Guillaume Racicot