Есть одно место, где подписанная версия std::size_t
(а также неподписанная версия std::ptrdiff_t
) встречается в стандарте: спецификатор формата printf
%zu
предназначен для объектов std::size_t
. %zd
предназначен для объектов, как указано в стандарте C, на который ссылается стандарт C ++, соответствующего целочисленного типа со знаком [из std::size_t
]
std::printf("%zu %zd %td %tu",
std::size_t{0}, std::make_signed_t<std::size_t>{0},
std::ptrdiff_t{0}, std::make_unsigned_t<std::ptrdiff_t>{0}
);
И поскольку не существует типа, специально названного для %zd
и %tu
, я склонен полагать, что не существует стандартного имени, как вы хотите (кроме как std::make_signed_t<std::size_t>
).
Кроме того, нет особых причин хотеть подписанный вариант std::size_t
: std::size_t
предназначен для размера объекта, а размер объекта не подписан.
ssize_t
гарантированно будет содержать либо -1
, либо неотрицательное значение. Гарантированный диапазон равен [-1, SSIZE_MAX]
(и это тип, специфичный для POSIX, а не стандартный тип C ++). Это потому, что он используется для значения без знака или -1 в случае ошибки.
В стандартной библиотеке C ++ для этого просто используется std::size_t
, а вместо std::size_t(-1) == SIZE_MAX
для указания ошибки / специального значения (см .: std::basic_string<...>::npos
, std::dynamic_extent
), поэтому вы можете просто использовать std::size_t
вместо ssize_t
, если вам нужно значение ошибки (или, может быть, std::optional<std::size_t>
).
Если вместо этого вы хотите, чтобы что-то представляло размер, но было подписано, std::ssize(c)
(подписано size
) вернет std::common_type_t<std::ptrdiff_t, std::make_signed_t<decltype(c.size())>>
. Для типов массивов std::ssize
возвращает std::ptrdiff_t
. Так что, наверное, для этой цели используйте std::ptrdiff_t
.
Если вам нужен тип, используемый для представления расстояния между двумя итераторами (включая указатели), для этого был создан std::ptrdiff_t
. Это в основном совпадает с концепцией размеров со знаком, и std::iterator_traits<...>::difference_type
обычно std::ptrdiff_t
.
Это не означает, что sizeof(std::ptrdiff_t) == sizeof(std::size_t)
. Стандарт не определяет никаких отношений между ними. Оба sizeof(std::ptrdiff_t) < sizeof(std::size_t)
и sizeof(std::ptrdiff_t) > sizeof(std::size_t)
кажутся теоретически возможными, но я не нашел ни одной системы, где бы это было так. Таким образом, простое утверждение должно работать на всех платформах и позволять вам просто использовать std::ptrdiff_t
:
static_assert(
sizeof(std::size_t) == sizeof(std::ptrdiff_t) &&
static_cast<std::size_t>(std::numeric_limits<std::ptrdiff_t>::max()) == std::numeric_limits<std::size_t>::max() / 2u,
"ptrdiff_t and size_t are not compatible"
);
(Во многих системах std::size_t
равно unsigned int
, а std::ptrdiff_t
равно signed long
, но sizeof(int) == sizeof(long)
, поэтому мы должны проверять диапазоны типов, а не std::is_same_v<std::ptrdiff_t, std::make_signed_t<std::size_t>>
)
Или просто используйте std::make_signed_t<std::size_t>
, как вы уже сделали.
person
Artyer
schedule
29.12.2020
static_assert
:static_assert(sizeof(std::size_t) == sizeof(std::ptrdiff_t), "error message");
. Это лучшее, что я знаю. - person NathanOliver   schedule 29.12.2020ptrdiff_t
можно использовать как подписанныйsize_t
, но вы должны проверить, чтобы убедиться? - person Arty   schedule 29.12.2020std::streamsize
используется как подписанный аналогstd::size_t
, аналогично Тип POSIXssize_t
. - person dxiv   schedule 29.12.2020ssize_t
не является стандартным C ++; это POSIX. Но на самом деле, если вам нужна подписанная версияsize_t
, то по-вашему, все в порядке. Я бы предположил, что стандартного нет, потому что отрицательных размеров на самом деле не существует, поэтому стандарт предпочитает более значимые имена, такие какptrdiff_t
, когда ему нужны такие вещи. - person HTNW   schedule 29.12.2020std::ssize
, но он может быть большеsize_t
. - person user975989   schedule 30.12.2020