Come stampare f std::vector<>::size_type?

Oct 11 2020

std::vectorha un tipo di membro size_type. Qual è il suo identificatore di formato printf?

Nota che size_typenon è identico a 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

Risposte

4 KamilCuk Oct 11 2020 at 20:55

Qual è il suo identificatore di formato printf?

Nessuno sa. Non è specificato cosa std::vector<?>::size_typesia esattamente, tranne per il fatto che si tratta di un "tipo intero senza segno" int C++ Container Library, General container Requirements . Poiché printfl'identificatore di formato dipende dal tipo, tutto dipende da una particolare implementazione. Potrebbe anche essere possibile che non esista un identificatore di printfformato.

Come stampare f std::vector<>::size_type?

A passi:

  1. Crea una libreria per ottenere l' identificatore di printfformattazione a seconda del tipo.
  2. Modella quella libreria su quel tipo.

È proprio lo stesso che std::cout::operator<<stanno facendo i sovraccarichi per la stampa comunque. Solo:

#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

Un umile trucco pratico

Sembra che non ci sia un modo elegante e diretto per farlo, come suggeriscono altre risposte. Cosa fare, allora? In mancanza di un approccio migliore, siamo umili e torniamo alle origini:

  1. Trova gli identificatori di formato printf per i tipi interi con segno e senza segno più grandi che puoi.
  2. In fase di compilazione, determinare la firma del vettore size_typeutilizzando std::is_signed_t<T>.
  3. In fase di esecuzione, verifica che il valore della dimensione sia sufficientemente piccolo da rientrare nel tipo di destinazione, altrimenti dichiara semplicemente l'errore.
  4. Trasmetti size_typeal tipo intero appropriato.
  5. È ora possibile utilizzare il valore cast in una chiamata printf.

PS - Per scegliere tra gli identificatori di formato firmato/non firmato, dovrai costruire la stringa di formato in modo dinamico, o scegliere tra due stringhe di formato o utilizzare la compilazione condizionale ecc. Invece, potresti semplicemente scegliere il tipo con segno più grande e trasmettere sempre in quello - al prezzo di fallire per le taglie più grandi che hanno bisogno dell'ultimo bit.