Jak wydrukować std :: vector <> :: size_type?

Oct 11 2020

std::vectorma typ członka size_type. Jaki jest jego specyfikator formatu printf?

Zauważ, że size_typeto nie jest identyczne z 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

Odpowiedzi

4 KamilCuk Oct 11 2020 at 20:55

Jaki jest jego specyfikator formatu printf?

Nikt nie wie. Nie określono, czym std::vector<?>::size_typedokładnie jest, z wyjątkiem tego, że jest to „typ liczby całkowitej bez znaku” int C ++ Container Library, Ogólne wymagania dotyczące kontenerów . Ponieważ printfspecyfikator formatu zależy od typu, wszystko zależy od konkretnej implementacji. Może się również zdarzyć, że nie istnieje printfspecyfikator formatu.

Jak wydrukować std :: vector <> :: size_type?

W krokach:

  1. Utwórz bibliotekę, aby uzyskać printfspecyfikator formatowania w zależności od typu.
  2. Skonfiguruj tę bibliotekę dla tego typu.

std::cout::operator<<Zresztą to to samo, co przeciążenie drukowania. Właśnie:

#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

Skromny, praktyczny hack

Wydaje się, że nie ma na to eleganckiego, prostego sposobu, jak sugerują inne odpowiedzi. Co więc robić? Z braku lepszego podejścia, bądźmy pokorni i wróćmy do podstaw:

  1. Znajdź specyfikatory formatu printf dla największych (pod względem rozmiaru) typów całkowitych ze znakiem i bez znaku, jakie możesz.
  2. W czasie kompilacji określ podpis wektora size_typeza pomocą std::is_signed_t<T>.
  3. W czasie wykonywania sprawdź, czy wartość rozmiaru jest wystarczająco mała, aby pasowała do typu docelowego, w przeciwnym razie po prostu zadeklaruj błąd.
  4. Rzutuj na size_typeodpowiedni typ liczby całkowitej.
  5. Możesz teraz użyć wartości rzutowania w wywołaniu printf.

PS - Aby wybrać między specyfikatorami formatu ze znakiem / bez znaku, musisz albo utworzyć ciąg formatu dynamicznie, albo wybrać między dwoma ciągami formatującymi, albo użyć kompilacji warunkowej itp. Zamiast tego możesz po prostu wybrać największy typ ze znakiem i zawsze rzutować w to - za cenę niepowodzenia w przypadku największych rozmiarów, które wymagają tego ostatniego bitu.