Doze novos recursos na saída formatada c++23

1. Introdução

Falando em saída formatada, é realmente difícil descrever em uma palavra, de assembly para C, para c++, para c#, Java, Python, Go... Quais nem todos estão usando seus próprios meios para mostrar seu coquetismo. Envolva-se no desenvolvimento de c++, muitas pessoas realmente usam printf. Mas essa função tem um problema fatal, ela só consegue imprimir coisas que ele mesmo pode brincar, se ele quiser mudar algo que não conhece, bom, vamos sonhar.
E o c++ também se sentiu desconfortável em usá-lo depois, afinal, eu sou C com classes, você não pode imprimir classes, isso não significa que a maior parte do trabalho não possa ser feita. Não tenho escolha a não ser criar uma entrada e saída de streaming sozinho, sobrecarregar o operador << e viver feliz para sempre. No entanto, certamente haverá no entanto.
No entanto, há um grande número de contêineres em STL, mas você não os suporta. Para um exemplo simples, há um std::vector e <<vec não pode ser usado diretamente. Em outras palavras, Ranges não são suportados , mas esta é uma questão importante do c++ 20. Recursos. Então std::format apareceu, mas por vários motivos, essa coisa é fácil de usar, mas a função é muito restrita e não suporta as operações de arquivo suportadas pela era do stream, e nem mesmo suporta o stream original support (std ::complex, e ainda tem uma atitude em relação a Ranges como suporte futuro).
Existem duas situações: uma é continuar a melhorar o std::format e a outra é introduzir o std::print (ou println, veja a definição padrão final). E os streams (std::cout e outros)? Pode ser eliminado por padrão.

2. std::formato de c++20

Não há necessidade de escrever printf e stream, todos estão familiarizados com isso. Vamos começar com std::format de c++20.
Vejamos um exemplo em cppreference.com:

#include <format>
#include <iostream>
#include <string>
#include <string_view>

template <typename... Args>
std::string dyna_print(std::string_view rt_fmt_str, Args&&... args) {
    return std::vformat(rt_fmt_str, std::make_format_args(args...));
}

int main() {
    std::cout << std::format("Hello {}!\n", "world");

    std::string fmt;
    for (int i{}; i != 3; ++i) {
        fmt += "{} "; // constructs the formatting string
        std::cout << fmt << " : ";
        std::cout << dyna_print(fmt, "alpha", 'Z', 3.14, "unused");
        std::cout << '\n';
    }
}

Sua saída é:

Hello world!
{}  : alpha
{} {}  : alpha Z
{} {} {}  : alpha Z 3.14

Em std::formatter, os tipos de dados básicos foram processados ​​por padrão, mas se o processamento for semelhante à classe personalizada, há duas maneiras de resolvê-lo, uma é herdar std::formatter para alcançar; o outro é faça você mesmo Realize as duas funções de analisar e formatar.
Dê uma olhada no exemplo anterior:
primeiro veja o que o cppreference fornece:

#include <format>
#include <iostream>

// 类型 T 的包装
template<class T>
struct Box
{
    T value;
};

// 能用被包装值的格式说明格式化包装 Box<T>
template<class T, class CharT>
struct std::formatter<Box<T>, CharT> : std::formatter<T, CharT>
{
    // 从基类继承 parse()

    // 通过以被包装值调用基类实现定义 format()
    template<class FormatContext>
    auto format(Box<T> t, FormatContext& fc)
    {
        return std::formatter<T, CharT>::format(t.value, fc);
    }
};

int main()
{
    Box<int> v = {42};
    std::cout << std::format("{:#x}", v);
}

Acompanhe isso:

template <typename _T1, typename _T2>
struct ABC {
	_T1 v1;
	_T2 v2;
};

template <typename _T1, typename _T2, typename _CharT>
struct std::formatter<ABC<_T1, _T2>, _CharT> : std::formatter<_T1, _CharT>
{	 
	template <typename _FormatContext>
	auto format(const ABC<_T1, _Ty2>& v, _FormatContext& format_context )
	{
		auto it = std::formatter<_T1, _CharT>::format(v.v1, format_context);
		it = '\n';
		it = std::formatter<_T2, _CharT>().format(v.v2, format_context);
		return it;
	}
};


#include <iostream>
void Test()
{
	ABC<int, double> abc{
	.v1 = 1,
		.v2 = 2.1
	};
	std::cout << std::format("abc = {}", abc);
}
int main()
{
	Test();
	return 1;
}

A segunda é que todos os interessados ​​podem fazer sozinhos, mas não acho que seja tão simples quanto operador<<.
Para obter mais informações, consulte:
https://zh.cppreference.com/w/cpp/utility/format/formatter

3. std::print em c++23

No novo padrão, existem diferentes métodos de processamento para contêineres associativos e contêineres não associados. De um modo geral, os contêineres associativos são relativamente simples e você pode perdê-lo diretamente. No entanto, para contêineres não rebeldes, como as séries Map e Set , pode Se você perder Ranges, você não gosta disso, então você mesmo precisa definir alguns formatos de saída como acima. Além disso, para alguns formulários especiais, como char array para string, alguns tipos não imprimíveis precisam ser processados. Por fim, todos sabem que também existe um adaptador de contêiner em STL, como eles lidam com isso?
Portanto, uma especificação é proposta na solução atualmente proposta: Range precisa ser inserido, o tipo de elemento pode ser formatado e o tipo de elemento não pode ser o próprio Range. Claro, visualizações, alguns formulários de referência e adaptadores de contêineres também são regulamentados. Por exemplo, o formato padrão é [item0, item1...], usando colchetes. E std::pair, std::tuple usam parênteses, outros podem se referir ao padrão mais recente.
Além disso, std::println também fornece alguns parâmetros semelhantes aos internos regulares, que podem remover algum conteúdo, como? O depurador que pode ser ignorado, n, remova a embalagem externa (ou seja, o par de colchetes externos), como como vários, o padrão final e o fornecedor do compilador prevalecerão.
Veja um exemplo:

std::println("{:?}", std::pair{3, 3}); // (3, 3)
std::println("{:n}", std::pair{3, 3}); // 3, 3
std::println("{:m}", std::pair{3, 3}); // 3: 3

Da mesma forma, todos esses são contêineres para os próprios Ranges do STL. E se for personalizado? Ainda precisa de std::range_formatter para formatar elementos personalizados. Meu Deus!

Quatro. Resumo

De qualquer forma, nesse aspecto, pode parecer simples, mas ainda não conseguiu refletir a simplicidade. Estima-se que os patrões também estejam coçando a cabeça. Deixe-os mexer lentamente e aguarde o resultado final. Se você puder usá-lo, use-o, se não puder usá-lo, ignore-o temporariamente. De qualquer forma, vai demorar muito para que o c++23 seja usado na engenharia. Atualmente, empresas que podem usar c++17 em engenharia já são empresas muito na moda.

Acho que você gosta

Origin blog.csdn.net/fpcc/article/details/131877938
Recomendado
Clasificación