Как определить настраиваемый кросс-платформенный тип size_t?

std::size_t обычно используется для индексирования массива и подсчета циклов. По определению std::size_t - это целочисленный тип без знака результата оператора sizeof, а также оператор sizeof... и alignof (начиная с С++ 11). Он определен в следующих заголовках:

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

Насколько я понимаю, тип, возвращаемый этими операторами, определяется при реализации.

Я хочу определить пользовательский size_t, чтобы избежать вытаскивания ненужных материалов из любого из заголовков, упомянутых выше, в файл .cpp, так как в моем файле мне нужно только std::size_t.

В С++ 11 и выше я думал, что могу использовать следующий псевдоним:

using size_t = decltype(sizeof(1));

Однако я хотел бы определить тип size_t для компиляторов pre-С++ 11 в переносном/межплатформенном виде.

Итак, есть ли переносимый способ определить size_t для pre-С++ 11?

Ответ 1

Хорошо теоретически, если листинг всех возможных (неподписанных) кандидатов для size_t не беспокоит вас, вы можете использовать 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:

Обходной путь для компиляторов, которые отличаются unsigned long от unsigned long long, несмотря на то, что они принимают 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]

Ответ 2

Насколько я знаю, вы указали только два кросс-платформенных способа получить size_t: включить определение из стандартного заголовка или decltype (начиная с С++ 11). Но оба они явно недоступны вам.

Третий вариант - ручной портирование, т.е. использование заранее определенных макросов для обнаружения среды и выбор правильного typedef из списка ручных команд typedefs. Например, в GCC вы можете использовать __SIZE_TYPE__ (однако рассмотрите предупреждение в документации о том, что макрос не должен использоваться напрямую и что он не предоставляется на всех платформах). В других компиляторах вы должны использовать что-то еще.

Ответ 3

К сожалению, "определяемый реализацией" включает файлы заголовков, а не только сам компилятор. Если вы посмотрите на [expr.sizeof], они, кажется, предлагают просто использовать это:

#include <cstddef>