std::print

std::print (ostream에 형식화 출력)

형식 문자열 fmt에 따라 args를 포맷하고 그 결과를 os 스트림에 삽입하는 함수예요. std::format의 출력 스트림 버전이며 C++23부터 있어요.

출처: cppreference

본문

<ostream> 헤더에 정의돼 있어요. C++23부터 std::print가 도입돼 formatted output을 표준 스트림에 직접 쓸 수 있게 됐어요.

template< class... Args >
void print( std::ostream& os, std::format_string<Args...> fmt, Args&&... args );

형식 문자열 fmt에 따라 args를 포맷하고, 그 결과를 os 스트림에 삽입해요.

일반 리터럴 인코딩이 UTF-8이면 다음과 동일해요.

  • std::vprint_unicode(os, fmt.get(), std::make_format_args(args...));. 그렇지 않으면,
  • std::vprint_nonunicode(os, fmt.get(), std::make_format_args(args...));.

Args의 어떤 Ti에 대해서도 std::formatter<Ti, char>BasicFormatter 요구사항을 만족하지 않으면(std::make_format_args가 요구하는 대로) 동작이 정의되지 않아요.

매개변수

  • os: 데이터를 삽입할 출력 스트림.

  • fmt: 형식 문자열을 나타내는 객체. 형식 문자열은 다음으로 구성돼요.

    • 출력으로 그대로 복사되는 일반 문자({} 제외),
    • 출력에서 각각 {}로 대체되는 이스케이프 시퀀스 {{}},
    • replacement fields.

    각 replacement field는 다음 형식을 가져요.

    { arg-id (optional) } (1), { arg-id (optional) : format-spec } (2).

    • (1) 형식 지정 없는 replacement field. (2) 형식 지정 있는 replacement field.
    • arg-id: 포맷에 사용할 args 안 인자의 인덱스를 지정해요. 생략하면 인자들이 순서대로 사용돼요. 형식 문자열의 arg-id들은 모두 있거나 모두 생략돼야 해요. 수동 인덱싱과 자동 인덱싱을 섞는 건 오류예요.
    • format-spec: 해당 인자에 대한 std::formatter 특수화가 정의한 형식 지정이에요. }로 시작할 수 없어요. 기본 타입·표준 문자열 타입은 표준 형식 지정, chrono 타입은 chrono 형식 지정, range 타입은 range 형식 지정, std::pair·std::tuple은 tuple 형식 지정으로 해석돼요. std::filesystem::path는 path 형식 지정(C++26)을, 그 외 포맷 가능 타입은 사용자 정의 formatter 특수화가 결정해요.
  • args...: 포맷할 인자들.

예외

  • 할당 실패 시 std::bad_alloc.
  • 어떤 formatter가 던지는 예외(예: std::format_error)는 os.exceptions() 값과 무관하게, os의 오류 상태에서 ios_base::badbit를 켜지 않고 전파돼요.
  • os로의 삽입이 실패하면 호출되는 os.setstate(ios_base::badbit) 때문에 생기는 ios_base::failure를 던질 수 있어요.

참고

피처 테스트 매크로 __cpp_lib_print(값 202207L, C++23, Formatted output)와 __cpp_lib_format(값 202207L, C++23, std::basic_format_string 노출)이 있어요.

예제를 보면요.

#include <array>
#include <cctype>
#include <cstdio>
#include <format>
#include <numbers>
#include <ranges>
#include <sstream>

int main()
{
    std::array<char, 24> buf;
    std::format_to(buf.begin(), "{:.15f}", std::numbers::sqrt2);

    unsigned num{}, sum{};

    for (auto n : buf
                | std::views::filter(isdigit)
                | std::views::transform([](char x) { return x - '0'; })
                | std::views::take_while([&sum](char) { return sum < 42; }))
        sum += n, ++num;

    std::stringstream stream;

#ifdef __cpp_lib_print
    std::print(stream,
#else
    stream << std::format(
#endif
        "√2 ≈ {0}.\n"
        "The sum of its first {1} digits is {2}.",
        std::numbers::sqrt2, num, sum
    );

    std::puts(stream.str().data());
}

출력은 다음과 같아요.

√2 ≈ 1.4142135623730951.
The sum of its first 13 digits is 42.

이렇게 std::printstd::format처럼 형식 지정을 지원하면서도 바로 ostream에 결과를 써줘요.

더 알아보기 (Learn more)

cppreference