Atualizei alguns códigos mais antigos para usar std::format
e fiquei surpreso ao descobrir que funcionava, apesar de eu ter esquecido de fornecer uma std::formatter
especialização para esse tipo.
Imediatamente fiz um pequeno programa de teste para tentar reproduzir isso, mas eles sempre apresentavam um erro de compilação, como eu esperava.
Depois de horas de depuração, descobri que, se o tipo personalizado tiver métodos públicos begin
e end
, a biblioteca formatará a sequência como uma lista separada por vírgulas entre colchetes.
P: Isso é um recurso definido por padrões std::format
ou um bug de implementação? (Ou outra coisa?)
Aqui está uma reprodução independente:
#include <array>
#include <print>
class MyType {
public:
MyType() : m_values{1, 2, 3, 4} {}
using internal_type = std::array<int, 4>;
using const_iterator = typename internal_type::const_iterator;
const_iterator cbegin() const { return m_values.cbegin(); }
const_iterator cend() const { return m_values.cend(); }
const_iterator begin() const { return cbegin(); }
const_iterator end() const { return cend(); }
private:
internal_type m_values;
};
int main() {
MyType foo;
// Since MyType is a user-defined type, I would not
// expect this print statement to compile without a
// specialization of std::formatter, but because
// it's iterable, it prints: "foo = [1, 2, 3, 4]\n".
std::print("foo = {}\n", foo);
return 0;
}
Estou usando o MS VC++ do Visual Studio 17.12.15 e compilando com /std:c++latest
.
A biblioteca padrão define uma
std::formatter
especialização para intervalos que começam em C++23:Existem algumas variações diferentes deste formatador de intervalo para sequências, conjuntos, mapas e strings. As regras padrão para cada um deles são:
R::key_type
eR::mapped_type
são definidos estd::remove_cvref_t<std::range_reference_t<R>>
é uma especialização destd::pair
oustd::tuple
com tamanho 2, então é um mapaR::key_type
for válido e um tipo, então é um conjuntoVocê pode controlar qual será selecionado por padrão, especializando o
std::format_kind
modelo para o seu tipo, ou sejaVocê pode selecionar explicitamente a string (com ou sem aspas e sequências de escape) ou o tipo de formato do mapa por meio da sua string de formato usando os especificadores
s
,?s
, e , respectivamente:m
Além disso, o especificador de formato pode ser usado para omitir os colchetes para tipos de intervalo diferentes de string. Isso também
n
pode ser combinado com o especificador:m
Demonstração ao vivo
Observe que, no momento da redação deste artigo (9 de abril de 2025), a libstdc++ (a biblioteca padrão usada pelo GCC) ainda não implementou essa funcionalidade.