Czy sizeof (wyliczenie) może różnić się od sizeof (typ: typ_podstawowy <Enum> :: typ)?

16

Niedawno pojawił się w przeglądzie kodu, który w następującym przykładzie:

enum class A : uint8_t
{
    VAL1, VAL2 
};

...
std::vector<A> vOfA; // Assume this is sized and full of some stuff.
std::memcpy(wire_buffer, vOfA.data(), vOfA.size() * sizeof(A));

Powinniśmy używać sizeof(std::underlying_type<A>::type)zamiast sizeof(A). Czy to możliwe, że mogą się one kiedykolwiek różnić? Czy ktoś ma ofertę cenową, która to gwarantuje?

Fantastyczny Mr Fox
źródło
Łączenie jaki jest rozmiar danych typu wyliczeniowego w C ++? (które powinny być również dostosowane do lunety :-).
Acorn,
3
Nawet jeśli mają ten sam rozmiar (co jest bardziej niż prawdopodobne), jaki jest argument przeciwko używaniu sizeof(A)? Ponadto: jeśli mają inny rozmiar (mało prawdopodobne), użycie sizeof(std::underlying_type<A>)byłoby po prostu złe.
Sander De Dycker,
1
sizeof(std::underlying_type<A>)jest prawdopodobnie 1. Miałeś na myśli ::type?
LF,
1
@SanderDeDycker Tak, kiedy mamy do czynienia z As, zdecydowanie chcemy używać, sizeof(A)a kod nie powinien przejmować się, jakiego rodzaju Ajest typ .
Acorn,
@LF Tak, literówka. Tytuł miał poprawny.
Fantastyczny Pan Lis,

Odpowiedzi:

12

W C ++ 03 było to gwarantowane (cóż, w każdym razie dla nieposkulonych wyliczeń).

[dcl.enum] Deklaracje wyliczeniowe ( wyróżnienie moje)

6 Podstawowy typ wyliczenia jest typem integralnym, który może reprezentować wszystkie wartości wyliczające zdefiniowane w wyliczeniu. Jeśli żaden typ całki nie może reprezentować wszystkich wartości modułu wyliczającego, wyliczenie jest źle sformułowane. Zdefiniowano implementację, który typ integralny jest używany jako typ bazowy dla wyliczenia, z tym wyjątkiem, że typ bazowy nie może być większy niż int, chyba że wartość modułu wyliczającego nie może zmieścić się w int lub int. Jeśli lista wyliczająca jest pusta, typem bazowym jest tak, jakby wyliczenie miało jeden wyliczający o wartości 0. Wartość sizeof()zastosowana do typu wyliczeniowego, obiektu typu wyliczeniowego lub wyliczającego jest wartością sizeof()zastosowaną do typ podstawowy .

Potem n2347 , papier, który został przyjęty do silnie typowanych wyliczeń ( enum class) i innych ulepszeń do nieskalowanych wyliczeń, i miał pogrubione zdanie. Co ciekawe, wcześniejsza wersja wniosku, n2213 , zastąpiła usunięte zdanie. Ale nie pasowało to do przyjętej wersji.

Tak więc we współczesnym C ++ nie ma obowiązku, aby rozmiary były takie same. Chociaż z praktycznego punktu widzenia implementacje raczej nie zmieniły zachowania określonego przez C ++ 03 dla wielkości wyliczeń.

Można uznać to za wadę standardu.

StoryTeller - Unslander Monica
źródło
2
Jak można zagwarantować coś w C ++ 03 dla funkcji, która nie istniała w tym języku? oO
Wyścigi lekkości na orbicie
4
@LightnessRaceswithMonica - Pojęcie typu bazowego nie jest nowe. Po prostu C ++ 11 pozwolił ci to określić sam.
StoryTeller - Unslander Monica,
Wiem to. Pojęcie enum o zasięgu ( enum class) jest nowe.
Wyścigi lekkości na orbicie
@LightnessRaceswithMonica - Myślę, że tutaj można potencjalnie zarzucić projektowi. Dokonał dwóch rzeczy, wprowadził wyliczenia o zasięgu i pozwolił, aby wszystkie wyliczenia (nie tylko o zasięgu) miały ustawiony typ bazowy. Stąd „gwarantowane” w C ++ 03.
StoryTeller - Unslander Monica,
1
@ StoryTeller-UnslanderMonica Tak, pytanie jest takie samo, myślę, że zakres lub nie.
Fantastyczny Pan Lis,