2017-06-13 19 views
12

std::size_t jest powszechnie używany do indeksowania tablic i liczenia pętli. Z definicji std::size_t jest liczbą całkowitą bez znaku wyniku operatora sizeof, a także operatora sizeof... i operatora alignof (od C++ 11). Jest zdefiniowana w następujących nagłówków:Jak zdefiniować niestandardowy typ wielkosci platformy?

  • <cstddef>
  • <cstdio>
  • <cstdlib>
  • <cstring>
  • <ctime>
  • <cwchar>

Do mojego un zgodnie z definicją, rodzaj zwracany przez tych operatorów jest określony przez implementację.

Co chcę jest zdefiniowanie niestandardowego size_t w celu uniknięcia niepotrzebnego ciągnąc rzeczy z jednego z wyżej wymienionych nagłówków w pliku kopalni .cpp, ponieważ w moim pliku tylko potrzebne std::size_t.

w C++ 11 i powyżej, Myślałem, że mogę użyć następującego Alias:

using size_t = decltype(sizeof(1)); 

Jednak chciałbym zdefiniować size_t typ do wstępnego C++ 11 kompilatorów w przenośnym/wieloplatformowy sposób.

Czy istnieje przenośny sposób definiowania size_t dla pre-C++ 11?

+3

Należy prawdopodobnie oznacz to pytanie C++ lub C++ 03 98, ale nie C++ 11, prawda? – Rakete1111

+12

* Dlaczego * nie chcesz dołączać żadnych standardowych plików nagłówkowych? Zazwyczaj nie są one tak duże i nie będą miały znaczącego wpływu na czas kompilacji. I jako te, w których 'size_t' jest zdefiniowany, tak naprawdę nie ma żadnych definicji funkcji w nich, co oznacza, że ​​nie będzie żadnego wygenerowanego dla nich kodu. Czy możesz rozwikłać problem * rzeczywisty *, który chcesz rozwiązać, definiując swój własny typ? –

+5

'cstddef' jest dość małym nagłówkiem, pod względem symboli. Czy to naprawdę zbyt dużo zanieczyszczeń w przestrzeni nazw, aby je ściągnąć? – StoryTeller

Odpowiedz

3

Więc teoretycznie, jeśli lista wszystkich możliwych (unsigned) kandydatów na size_t nie przeszkadza, można skorzystać z SFINAE:

template <class T, class N = void, bool = sizeof(T) == sizeof(sizeof(T))> 
struct TL { 
    typedef typename N::type type; 
}; 

template <class T, class N> 
struct TL<T, N, true> { 
    typedef T type; 
}; 

typedef TL<unsigned short,TL<unsigned int, TL<unsigned long, TL<unsigned long long> > > >::type SizeT; 

[live demo]


Edit:

Obejście dla kompilatorów, które różnicują unsigned long z unsigned long long pomimo faktu, że są one przy założeniu sizeof(unsigned long) == sizeof(unsigned long long):

template <class U> 
U *declptrval(U); 

template <class U> 
char is_exact(U *); 

template <class U> 
short is_exact(...); 

template <class T, class N = void, bool = sizeof(is_exact<T>(declptrval(sizeof(T))))==sizeof(char)> 
struct TL { 
    typedef typename N::type type; 
}; 

template <class T, class N> 
struct TL<T, N, true> { 
    typedef T type; 
}; 

typedef TL<unsigned short,TL<unsigned int, TL<unsigned long, TL<unsigned long long> > > >::type SizeT; 

[live demo]

+1

Dude, jaki rodzaj czarów to jest?!?!?!?!?! – 101010

+0

@ 101010 Możesz nazywać mnie Houdini;) –

0

Niestety, "zdefiniowane przez implementację" obejmuje pliki nagłówkowe, a nie tylko sam kompilator. Jeśli spojrzeć na [expr.sizeof], zdają się sugerować, właśnie za pomocą tego:

#include <cstddef> 
+0

OP zawiera już listę' ' – NathanOliver

+0

Wiem. Po prostu zwracam uwagę, że standardy C++ są nieco dziwne, ponieważ nie wymagają wbudowanych funkcji językowych (takich jak sizeof i [typid] (http://eel.is/c++draft/expr.typeid)) koniecznie są wspierane przez wbudowane typy (które nie muszą zawierać). –

4

O ile mi wiadomo, pan wymienił tylko dwa sposoby, cross-platform, aby uzyskać size_t: Dołącz definicję ze standardowego nagłówka, lub decltype (od C++ 11). Ale oba są jawnie niedostępne.

Trzecią opcją jest ręczne portowanie, tj. Użycie zdefiniowanych makr do wykrywania środowiska i wybór właściwego typu z ręcznie zarządzanej listy typów. Na przykład na GCC można użyć __SIZE_TYPE__ (należy jednak wziąć pod uwagę ostrzeżenie w dokumentacji, że makro nie powinno być używane bezpośrednio i że nie jest dostępne na wszystkich platformach). W innych kompilatorach możesz użyć czegoś innego.