Como imprimir std :: vector <> :: size_type?

Oct 11 2020

std::vectortem um tipo de membro size_type. Qual é o seu especificador de formato printf?

Observe que size_typenão é idêntico 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

Respostas

4 KamilCuk Oct 11 2020 at 20:55

Qual é o seu especificador de formato printf?

Ninguém sabe. Não é especificado o que std::vector<?>::size_typeexatamente é, exceto que é um "tipo inteiro sem sinal" na Biblioteca de contêineres C ++, Requisitos gerais de contêiner . Como o printfespecificador de formato depende do tipo, tudo depende de uma implementação específica. Também pode ser possível que não exista um printfespecificador de formato.

Como imprimir std :: vector <> :: size_type?

Em etapas:

  1. Crie uma biblioteca para obter o printfespecificador de formatação dependendo do tipo.
  2. Molde essa biblioteca nesse tipo.

É exatamente o mesmo que as std::cout::operator<<sobrecargas estão fazendo com a impressão. Somente:

#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

Um humilde hack prático

Parece não haver uma maneira simples e elegante de fazer isso, como sugerem outras respostas. O que fazer então? Por falta de uma abordagem melhor, sejamos humildes e voltemos ao básico:

  1. Encontre especificadores de formato printf para os maiores tipos de inteiros assinados e não assinados (em termos de tamanho) que você puder.
  2. Em tempo de compilação, determine a sinalização do vetor size_typeusando std::is_signed_t<T>.
  3. Em tempo de execução, verifique se o valor do tamanho é pequeno o suficiente para caber no tipo de destino, caso contrário, apenas declare a falha.
  4. Converta o size_typepara o tipo inteiro apropriado.
  5. Agora você pode usar o valor de conversão em uma chamada printf.

PS - Para escolher entre os especificadores de formato assinado / não assinado, você precisará construir a string de formato dinamicamente ou escolher entre duas strings de formato ou usar compilação condicional etc. para isso - ao preço de falhar para os tamanhos maiores que precisam desse último pedaço.