제목: “이번 주의 팁 #215: AbslStringify()를 사용한 사용자 정의 타입 문자열화”

원문 게시일: 2022년 11월 2일
업데이트: 2022년 11월 16일

작성자: Phoebe Liang

빠른 링크: abseil.io/tips/215


개요

Abseil은 사용자 정의 타입을 문자열로 포맷할 수 있는 새로운 경량 메커니즘인 **AbslStringify()**를 지원합니다. AbslStringify()를 확장한 사용자 정의 타입은 absl::StrFormat, absl::StrCat, 그리고 absl::Substitute와 함께 바로 사용할 수 있습니다.

대부분의 타입 확장과 마찬가지로, 확장하려는 타입을 직접 소유하고 있어야 합니다.


사용 예제

간단한 Point 구조체를 예로 들어보겠습니다:

CPP
struct Point {
  int x;
  int y;
};
클릭하여 더 보기

Pointabsl::StrFormat(), absl::StrCat()absl::Substitute()에서 사용하고 싶다면, AbslStringify()라는 friend 함수 템플릿을 추가하면 됩니다:

CPP
struct Point {
  template <typename Sink>
  friend void AbslStringify(Sink& sink, const Point& p) {
    absl::Format(&sink, "(%d, %d)", p.x, p.y);
  }

  int x;
  int y;
};
클릭하여 더 보기

참고: AbslStringify()는 문자열을 생성하기 위해 제네릭 “sink” 버퍼를 사용합니다. 이 sink는 absl::FormatSink와 유사한 인터페이스를 가지지만, PutPaddedString()은 지원하지 않습니다.

이제 absl::StrCat("The point is ", p)absl::Substitute("The point is $0", p)를 사용할 수 있습니다.


%v 타입 지정자와 타입 유추

absl::StrFormat()을 사용해 타입을 포맷하고 싶다면 어떻게 해야 할까요? 기존의 타입 지정자는 AbslStringify()를 확장한 사용자 정의 타입을 지원하지 않기 때문에 다음과 같이 작성해야 합니다:

CPP
absl::StrFormat("The point is (%d, %d)", p.x, p.y);
클릭하여 더 보기

하지만 이는 비효율적입니다. 포맷 문자열을 반복해야 하고 AbslStringify() 확장을 사용하지도 않습니다. 대신 새로운 %v 타입 지정자를 사용할 수 있습니다:

CPP
absl::StrFormat("The point is %v", p);
클릭하여 더 보기

%v는 타입 유추를 통해 인자를 포맷합니다. %v는 대부분의 기본 타입과 AbslStringify()로 확장된 타입을 지원합니다. %v를 사용하면 “값"을 범용적으로 포맷할 수 있습니다.


%v가 유추하는 타입

주의: const char*는 지원되지 않습니다.


예제

CPP
absl::StrFormat("%v", std::string{"hello"}) -> "hello"
absl::StrFormat("%v", 42) -> "42"
absl::StrFormat("%v", uint64_t{16}) -> "16"
absl::StrFormat("%v", 1.6) -> "1.6"
absl::StrFormat("%v", true) -> "true"
클릭하여 더 보기

다른 라이브러리와의 통합

로깅 지원

AbslStringify()를 정의한 타입은 바로 로깅에 사용할 수 있습니다:

CPP
struct Point {
  template <typename Sink>
  friend void AbslStringify(Sink& sink, const Point& p) {
    absl::Format(&sink, "(%v, %v)", p.x, p.y);
  }

  int x = 10;
  int y = 20;
};

Point p;

LOG(INFO) << p;
클릭하여 더 보기

이 코드의 로그 출력 결과는 다음과 같습니다:

PLAINTEXT
I0926 09:00:00.000000   12345 main.cc:10] (10, 20)
클릭하여 더 보기

operator<< 대신 AbslStringify()를 구현하는 것을 권장합니다. 이렇게 하면 absl::StrFormat, absl::StrCat, absl::Substitute에서도 사용할 수 있기 때문입니다.


프로토콜 버퍼 지원

프로토콜 버퍼도 AbslStringify()를 통해 문자열로 포맷할 수 있습니다:

CPP
message MyProto {
  optional string my_string = 1;
}

MyProto my_proto;
my_proto.set_my_string("hello world");

absl::StrCat("My proto is: ", my_proto);
absl::StrFormat("My proto is: %v", my_proto);
LOG(INFO) << my_proto;
클릭하여 더 보기

마무리

%v 타입 지정자는 “그냥 사람이 읽을 수 있는 형태로 출력"하는 것이 목적입니다. 사용자 정의 타입과 같이 필요한 경우를 제외하고는 %v를 간단한 포맷팅에 사용하는 것을 추천합니다. 하지만 더 세부적인 포맷이 필요한 경우에는 기존의 타입 지정자를 사용해야 합니다.

라이선스

저작자: Jaehun Ryu

링크: https://jaehun.me/posts/abseil-tip-215-abslstringify%EB%A5%BC-%EC%82%AC%EC%9A%A9%ED%95%9C-%EC%82%AC%EC%9A%A9%EC%9E%90-%EC%A0%95%EC%9D%98-%ED%83%80%EC%9E%85-%EB%AC%B8%EC%9E%90%EC%97%B4%ED%99%94/

라이선스: CC BY 4.0

이 저작물은 크리에이티브 커먼즈 저작자표시 4.0 국제 라이선스에 따라 이용할 수 있습니다. 출처를 밝히면 상업적 목적을 포함해 자유롭게 이용 가능합니다.

댓글

검색 시작

검색어를 입력하세요

↑↓
ESC
⌘K 단축키