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

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

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

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

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

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

using size_t = decltype(sizeof(1));

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

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


person 101010    schedule 13.06.2017    source источник
comment
Вероятно, вам следует пометить этот вопрос как C++03 или C++98, но не C++11, верно?   -  person Rakete1111    schedule 13.06.2017
comment
Почему вы не хотите включать какие-либо стандартные заголовочные файлы? Обычно они не такие большие и не будут заметно влиять на время компиляции. И поскольку те, где определено size_t, на самом деле не имеют никаких определений функций, это означает, что для них также не будет сгенерирован какой-либо код. Не могли бы вы подробнее рассказать о фактической проблеме, которую вы хотите решить, определив свой собственный тип подобным образом?   -  person Some programmer dude    schedule 13.06.2017
comment
cstddef — довольно маленький заголовок с точки зрения символов. Действительно ли слишком много загрязнения пространства имен, чтобы втянуть его?   -  person StoryTeller - Unslander Monica    schedule 13.06.2017
comment
Вы можете переделать boost::typeof   -  person NathanOliver    schedule 13.06.2017
comment
спасает ли определение пользовательского типа от включения заголовка, содержащего стандартное определение? в любом случае любые стандартные типы контейнеров имеют size_type, которые вы можете использовать   -  person phuclv    schedule 13.06.2017


Ответы (3)


Ну теоретически, если перечисление всех возможных (без знака) кандидатов на 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;

[демонстрация]


Изменить:

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

[демонстрация]

person W.F.    schedule 13.06.2017
comment
Чувак, что это за колдовство?!?!?!?!?! - person 101010; 13.06.2017
comment
@101010 Можешь звать меня Гудини ;) - person W.F.; 13.06.2017

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

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

person eerorika    schedule 13.06.2017

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

#include <cstddef>
person David A    schedule 13.06.2017
comment
Я знаю. Я просто указываю на то, что стандарты C++ немного странные, поскольку они не требуют встроенных функций языка (таких как sizeof и typeid) обязательно должны поддерживаться встроенными типами (которые не требуют включения). - person David A; 13.06.2017