Twelve new features in c++23 formatted output

1. Introduction

Speaking of formatted output, it's really hard to describe in one word, from assembly to C, to c++, to c#, Java, Python, Go... Which ones are not all using their own means to show their coquettishness. Engage in c++ development, many people actually use printf. But this function has a fatal problem, it can only print things that he can play with himself, if he wants to change something he doesn't know, well, let's dream.
And c++ also felt uncomfortable to use it later, after all, I am C with classes, you can't print classes, that doesn't mean most of the work can't be done. I have no choice but to create a streaming input and output by myself, overload operator<<, and live happily ever after. However, there will certainly be however.
However, there are a large number of containers in STL, but you don’t support them. For a simple example, there is a std::vector, and <<vec cannot be used directly. In other words, Ranges are not supported, but this is a major issue of c++20. Features. So std::format appeared, but due to various reasons, this thing is easy to use, but the function is too narrow, and it does not support the file operations supported by the stream era, and it does not even support the original stream support (std ::complex, and still have an attitude towards Ranges as future support).
There are two situations: one is to continue to improve std::format, and the other is to introduce std::print (or println, see the final standard definition). What about streams (std::cout and others)? It may be eliminated by default.

2. std::format of c++20

There is no need to write printf and stream, everyone is very familiar with it. Let's start with std::format of c++20.
Let's look at an example on 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';
    }
}

Its output is:

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

In std::formatter, the basic data types have been processed by default, but if the processing is similar to the custom class, there are two ways to solve it, one is to inherit std::formatter to achieve; the other is to do it yourself Realize the two functions of parse and format.
Take a look at the former example:
first look at what cppreference provides:

#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);
}

Follow this up:

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;
}

The second is that everyone who is interested can do it by themselves, but I don’t think it is as simple as operator<<.
For more information, please refer to:
https://zh.cppreference.com/w/cpp/utility/format/formatter

3. std::print in c++23

In the new standard, there are different processing methods for associative containers and non-associated containers. Generally speaking, associative containers are relatively simple, and you can just lose it directly. However, for non-rebellious containers, such as Map and Set series, it may If you lose Ranges, you don't like it, so you need to define some output formats yourself as above. In addition, for some special forms, such as char array to string, some unprintable types need to be processed. Finally, everyone knows that there is also a container adapter in STL, how do they deal with it?
Therefore, a specification is proposed in the currently proposed solution: Range needs to be input, the element type can be formatted and the element type cannot be Range itself. Of course, views, some reference forms and container adapters are also regulated. For example, the default format is [item0, item1...], using square brackets. And std::pair, std::tuple use parentheses, others can refer to the latest standard.
In addition, std::println also provides some parameters similar to regular internals, which can remove some content, such as? The debugger that can be ignored, n, remove the outer packaging (that is, the pair of brackets outside), such as various, The final standard and compiler vendor shall prevail.
See an example:

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

Similarly, these are all containers for STL's own Ranges. What if it is customized? Still need std::range_formatter to format custom elements. My God!

Four. Summary

Anyway, in this aspect, it may seem simple, but it has not been able to reflect the simplicity yet. It is estimated that the bosses are also scratching their heads. Let them toss slowly and wait for the final result. If you can use it, use it, if you can't use it, just temporarily bypass it. Anyway, it will take a long time for c++23 to be used in engineering. At present, companies that can use c++17 in engineering are already very trendy companies.

Guess you like

Origin blog.csdn.net/fpcc/article/details/131877938