2010-01-25 10 views
17

Wiem, że sizeof jest obliczaniem czasu kompilacji, ale wydaje mi się to dziwne: Kompilator może przyjmować nazwę typu lub wyrażenie (z którego dedukuje typ). Ale jak rozpoznać typ w klasie? Wydaje się, że jedynym sposobem jest przekazanie wyrażenia, które wydaje się dość niezgrabne.Dlaczego sizeof nie przetwarza elementów konstrukcyjnych?

struct X { int x; }; 
int main() { 
    // return sizeof(X::x); // doesn't work 
    return sizeof(X()::x); // works, and requires X to be default-constructible 
} 
+11

Wsparcie dla 'sizeof (X :: x)' jest w C++ 0x (por http://www.open -std.org/jtc1/sc22/wg21/docs/papers/2007/n2253.html). –

+0

@James +1 przy Twoim komentarzu. Moja odpowiedź (usunięta) powinna być właściwie komentarzem, ponieważ Tom nie wspomniał o C++ 0x. Może on tego chce w C++ 98 :) – AraK

+0

Tak, moje pytanie dotyczy C++ 98. Jednak nawet jeśli buduję z '-std = C++ 0x', to nie działa (GCC 4.3.2). Czy są jakieś implementacje kompilatorów, które jeszcze ją obsługują? – Tom

Odpowiedz

27

Alternatywna metoda działa bez konieczności domyślnego konstruktora:

return sizeof(((X *)0)->x); 

można zawinąć to w makro tak to brzmi lepiej:

#define member_sizeof(T,F) sizeof(((T *)0)->F) 
+0

AFAIK, dereferencja wskaźnika NULL jest niezdefiniowanym zachowaniem. Czy ta zasada obowiązuje również w tym przypadku? – AraK

+5

@AraK: Nie sądzę: "Operand [sizeof] jest albo wyrażeniem, * które nie jest oceniane *, albo rodzicielskim id-typu" (5.3.3/1; –

+2

NULL wskaźnik nigdy nie jest dereferenced. Jest to operacja w czasie kompilacji. Chodzi o to, aby kompilator wykonał The Right Thing (tm). –

0

Co offsetof? Spójrz na here. Zobacz także here, który łączy w jedno makro zarówno sizeof i offsetof.

Mam nadzieję, że to pomoże.

+0

Nie pomaga, ponieważ kompilator (podczas gdy wymagane jest zamówienie elementów konstrukcji w zadeklarowanej kolejności) ma swobodę do umieszczania ich zgodnie z potrzebami. – dmckee

+0

dmckee: Oh, Ok..dzięki za twój wkład! Pozdrawiam :) – t0mm13b

10

Oto rozwiązanie bez nieprzyjemnych zerowy wskaźnik dereferencing;)

struct X { int x; }; 

template<class T> T make(); // note it's only a declaration 

int main() 
{ 
    std::cout << sizeof(make<X>().x) << std::endl; 
} 
+0

oh, to jest trix! – Tom

+1

Nie możesz po prostu powiedzieć 'extern T fakeT; sizeof (fakeT.x); '? – MSalters