c++23中的print和println

一、格式化控制

人类和计算机交互过程中,一定会有一种数据格式化的过程。这个很好理解,两种不同的语言交互还需要一个翻译呢,对吧?从开始学习编程的std::cout系列和C语言中的printf函数,以及后面各种更高级的格式化函数sprintf,fprintf等,都说明这个需求是一个强需求。

C++从C++20中的formatting开始,就进行了一些更高级一些应用场景的支持,而在C++23中则提供了更容易为广大开发者接受的std::print和std::println。

二、C++23中的std::print和std::println

下面就对std::print和std::println具体内容进行分析和说明:

  1. std::print和std::println的定义

    c 复制代码
    //头文件 <print>
    //print
    template< class... Args >
    void print( std::format_string<Args...> fmt, Args&&... args );
    
    template< class... Args >
    void print( std::FILE* stream,
    	    std::format_string<Args...> fmt, Args&&... args );
    	    
    //println
    template< class... Args >
    void println( std::format_string<Args...> fmt, Args&&... args );
    template< class... Args >
    
    void println( std::FILE* stream,
    	      std::format_string<Args...> fmt, Args&&... args );
    void println();   (3) 	(since C++26)
    void println( std::FILE* stream );   	(4) 	(since C++26)

后面的两个在C++26中支持,大家暂时可以忽略。两个函数一个最重要的不同在于,println会自动在处理完成格式后在其后面添加一个"\n"的换行符。

  1. 功能特点

做为C++23中新推出的格式化函数接口,只能说明一件事,原来的标准中的格式化接口可能有着这样或那样的不足。做为C++23的新接口,std::print和std::println支持默认输出输入流上处理,同样也支持指定文件流的处理。它的主要特点包括:

类型安全:这是C++一直强调和发展的方向。std::print和std::println通过可变参数模板,通过完美转发来保证数据类型的安全

支持宽字符(Unicode):这个是高级语言的必备。在POSIX中,这是一种默认设置而在Windows上,可通过编译开关"utf-8"来开启应用

支持自定义类型:可以利用std::format相同的机制来实现自定义类型的格式化

与C兼容:支持直接操作C中的文件流等

在使用这两个格式化函数出现问题时,有以下几种情况:分配失败时异抛出异常std::bad alloc;写入流失败,会报std::system_error系统错误。而格式化程序抛出的任何异常可由std::format error等错误机制处理。

  1. 语法说明
    这两个新的格式化函数接口,一般是通过通过字符串(除"{"和"}")、转义字符"{{"和"}}"(会替换为"{"和"}")以及相关替换的字段(变量等),其相关的语法为:

    复制代码
    { arg-id (optional) } 		//无格式化说明
    { arg-id (optional) : format-spec } 	//有格式化说明

其中,arg-id用于指定 args中用于格式化的值的参数索引,如果省略,则按顺序使用参数。format-spec是由 std::formatter特化版本定义的格式说明,但不能以"}"开头。另外,其还支持本地化的格式化处理,即大写的L用于指示输出采用本地环境(地域化)的特定形式。

  1. 与其它方式的区别

开发者常用的输出方式常见的还有C语言中的printf和std::cout等。对于前者,C++23这两个接口函数std::print和std::println更安全、方便且支持自定义类型;而对于后者,std::print和std::println格式化能力更强大且应用上更简洁。

三、例程

下面看一下这两个函数的具体的例程:

c 复制代码
//print
#include <cstdio>
#include <filesystem>
#include <print>
 
int main()
{
    std::print("{2} {1}{0}!\n", 23, "C++", "Hello");  // overload (1)
 
    const auto tmp{std::filesystem::temp_directory_path() / "test.txt"};
    if (std::FILE* stream{std::fopen(tmp.c_str(), "w")})
    {
        std::print(stream, "File: {}", tmp.string()); // overload (2)
        std::fclose(stream);
    }
    
    std::vector<int> vec = {11, 32, 77};
    std::print("vec elements: {}\n", vec);
    
    return 0;
}
//println
#include <print>

int main() {

    std::println("Hello!");

    double val = 3.18;
    std::string test{ "Hello" };
    std::println("{} - {} !", test, val);

    return 0;
}

上面的代码比较简单,大家主要是看清楚怎么用,可以自己编译一下代码并查看一下具体的输出。

四、总结

标准的完善和修改,是需要一个不断演进的过程。正如此次分析的std::print和std::println,它分析总结了前面可用的相关输出函数的优缺点并在此基础上进行了演化。使得开发者可以更方便、简单、快捷的应用格式化的输出。标准的演进过程,也是开发者学习的演进过程,这为开发者提供了一条可供借鉴的方式。

相关推荐
玉树临风江流儿2 小时前
C++左值、右值、move移动函数
开发语言·c++
许长安3 小时前
c/c++ static关键字详解
c语言·c++·经验分享·笔记
Murphy_lx4 小时前
C++ thread类
开发语言·c++
月夜的风吹雨4 小时前
【C++ STL 深度剖析】:vector 底层模拟实现与核心陷阱解析
c++·vector·类和对象·visual studio
彩妙不是菜喵4 小时前
C++ 中 nullptr 的使用与实践:从陷阱到最佳实践
开发语言·jvm·c++
_dindong5 小时前
笔试强训:Week-4
数据结构·c++·笔记·学习·算法·哈希算法·散列表
liu****6 小时前
12.线程(二)
linux·开发语言·c++·1024程序员节
小冯的编程学习之路7 小时前
【C++】:C++基于微服务的即时通讯系统(2)
开发语言·c++·微服务
许长安7 小时前
C/C++中的extern关键字详解
c语言·开发语言·c++·经验分享·笔记