Как распечатать std :: vector <> :: size_type?

Oct 11 2020

std::vectorимеет тип члена size_type. Каков его спецификатор формата printf?

Обратите внимание, что size_typeэто не идентично size_t.
https://en.cppreference.com/w/cpp/container/vector
https://en.cppreference.com/w/cpp/types/size_t
https://en.cppreference.com/w/cpp/io/c/fprintf

Ответы

4 KamilCuk Oct 11 2020 at 20:55

Каков его спецификатор формата printf?

Никто не знает. Не указано, что std::vector<?>::size_typeименно, за исключением того, что это «целочисленный тип без знака» int Библиотека контейнеров C ++, Общие требования к контейнерам . Поскольку printfспецификатор формата зависит от типа, все зависит от конкретной реализации. Также возможно, что не существует printfспецификатора формата.

Как распечатать std :: vector <> :: size_type?

По шагам:

  1. Создайте библиотеку для получения printfспецификатора форматирования в зависимости от типа.
  2. Шаблон этой библиотеки для этого типа.

В std::cout::operator<<любом случае это то же самое, что и перегрузки для печати. Просто:

#include <cstdlib>
#include <string>
#include <cstdio>
#include <vector>

template<typename T> constexpr const char *get_printf_formatting_spec() noexcept;
template<> constexpr const char *get_printf_formatting_spec<std::size_t>() noexcept {
    return "zu";
}
template<> constexpr const char *get_printf_formatting_spec<unsigned long long>() noexcept {
    return "llu";
}
/// etc.

int main() {
    const auto fmt = std::string() + 
        "%" +
        get_printf_formatting_spec<std::vector<int>::size_type>() +
        "\n";
    std::printf(fmt.c_str(), static_cast<std::vector<int>::size_type>(1));
}
1 einpoklum Oct 12 2020 at 15:03

Скромный практический совет

Кажется, что нет элегантного и простого способа сделать это, как предполагают другие ответы. Что же тогда делать? Из-за отсутствия лучшего подхода давайте будем скромными и вернемся к основам:

  1. Найдите спецификаторы формата printf для самых больших (по размеру) целочисленных типов со знаком и без знака, которые вы можете.
  2. Во время компиляции определите подписанность вектора, size_typeиспользуя std::is_signed_t<T>.
  3. Во время выполнения убедитесь, что значение размера достаточно мало, чтобы соответствовать целевому типу, в противном случае просто объявите сбой.
  4. Приведите size_typeк соответствующему целочисленному типу.
  5. Теперь вы можете использовать значение приведения в вызове printf.

PS - Чтобы выбрать между спецификаторами формата со знаком / без знака, вам нужно будет либо создать строку формата динамически, либо выбрать одну из двух строк формата, либо использовать условную компиляцию и т. Д. Вместо этого вы можете просто выбрать самый большой подписанный тип и всегда приводить в это - ценой неудачи для самых больших размеров, которым нужен последний бит.