제목: “이번 주의 팁 #215: AbslStringify()를 사용한 사용자 정의 타입 문자열화”
원문 게시일: 2022년 11월 2일
업데이트: 2022년 11월 16일
작성자: Phoebe Liang
빠른 링크: abseil.io/tips/215
개요
Abseil은 사용자 정의 타입을 문자열로 포맷할 수 있는 새로운 경량 메커니즘인 **AbslStringify()**를 지원합니다. AbslStringify()를 확장한 사용자 정의 타입은 absl::StrFormat, absl::StrCat, 그리고 absl::Substitute와 함께 바로 사용할 수 있습니다.
대부분의 타입 확장과 마찬가지로, 확장하려는 타입을 직접 소유하고 있어야 합니다.
사용 예제
간단한 Point 구조체를 예로 들어보겠습니다:
struct Point {
int x;
int y;
};Point를 absl::StrFormat(), absl::StrCat() 및 absl::Substitute()에서 사용하고 싶다면, AbslStringify()라는 friend 함수 템플릿을 추가하면 됩니다:
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()를 확장한 사용자 정의 타입을 지원하지 않기 때문에 다음과 같이 작성해야 합니다:
absl::StrFormat("The point is (%d, %d)", p.x, p.y);하지만 이는 비효율적입니다. 포맷 문자열을 반복해야 하고 AbslStringify() 확장을 사용하지도 않습니다. 대신 새로운 %v 타입 지정자를 사용할 수 있습니다:
absl::StrFormat("The point is %v", p);%v는 타입 유추를 통해 인자를 포맷합니다. %v는 대부분의 기본 타입과 AbslStringify()로 확장된 타입을 지원합니다. %v를 사용하면 “값"을 범용적으로 포맷할 수 있습니다.
%v가 유추하는 타입
- 정수형:
d(부호 있는 정수) - 부호 없는 정수형:
u - 부동소수점:
gdouble,float,long double
- 문자열:
sstd::string,absl::string_view,std::string_view,absl::Cord
주의:
const char*는 지원되지 않습니다.
예제
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()를 정의한 타입은 바로 로깅에 사용할 수 있습니다:
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;이 코드의 로그 출력 결과는 다음과 같습니다:
I0926 09:00:00.000000 12345 main.cc:10] (10, 20)operator<< 대신 AbslStringify()를 구현하는 것을 권장합니다. 이렇게 하면 absl::StrFormat, absl::StrCat, absl::Substitute에서도 사용할 수 있기 때문입니다.
프로토콜 버퍼 지원
프로토콜 버퍼도 AbslStringify()를 통해 문자열로 포맷할 수 있습니다:
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를 간단한 포맷팅에 사용하는 것을 추천합니다. 하지만 더 세부적인 포맷이 필요한 경우에는 기존의 타입 지정자를 사용해야 합니다.
댓글