(전체가 아니라 C#과 차이가 있는 부분을 중심으로 요약 정리)

Ratio 라이브러리

ratio 라이브러리를 이용하면 유한 유리수(finite rational number)를 컴파일 시간에 정확히 표현할 수 있다. 유리수는 다음 절에서 설명할 std::chrono::duration 클래스에서 사용된다. 이 라이브러리에 관련된 내용은 모두 <ratio> 헤더 파일의 std 네임스페이스 아래에 정의돼 있다.

유리수를 구성하는 분자와 분모는 std::intmax_t 타입의 컴파일 상수로 표현한다. 이 타입은 부호 있는 저웃 타입으로 최댓값은 컴파일러마다 다르다. 여기서 제공하는 유리수는 컴파일 시간에 결정되기 때문에 다른 타입에 비해 사용법이 다소 복잡해 보일 수 있다.

ratio 객체를 정의하는 방식은 일반 객체와 다르다. 메서드를 호출할 수 없으며 타입 앨리어스처럼 사용해야 한다. 예컨대 1/60이라는 유리수를 컴파일 시간 상수로 선언하면 다음과 같다.

using r1 = ratio<1, 60>

r1 유리수의 분자와 분모는 컴파일 시간 상수이며 다음과 같이 접근한다.

intmax_t num = r1::num;
intmax_t den = r1::den;

다시 한 번 강조하면 ratio는 컴파일 시간 상수(compile-time constant)라서 분자와 분모가 컴파일 시간에 결정된다. 따라서 다음과 같이 작성하면 컴파일 에러가 발생한다.

intmax_t n = 1;
intmax_t d = 60;
using r1 = ratio<n, d>; // error

유리수는 항상 정규화(normalized, 약분)된 상태로 표현된다.  유리수 ratio<n, d>에 대해 최대공약수가 gcd일 때 분자 nm과 분모 den은 다음과 같이 결정된다.

ratio 라이브러리는 유리수의 덧셈, 뺄셈, 곱셈, 나눗셈을 지원한다. 이 연산도 모두 컴파일 시간에 처리된다. 그래서 표준 산술 연산을 적용할 수 없고, 타입 앨리어스를 이용한 특수 템플릿으로 처리해야 한다.

이러한 용도로 제공되는 산술 ratio 템플릿으로는 ratio_add, ratio_subtract, ratio_multiply, ratio_divide가 있다. 이 템플릿은 계산 결과를 새로운 ratio 타입으로 표현한다. 이 타입은 C++에 정의된 type이라는 타입 앨리어스로 접근한다.

예컨대 다음 코드는 1/60과 1/30에 대한 ratio 값을 정의한다. 그런 다음 ratio_add 템플릿으로 두 유리수를 더해서 result란 유리수를 구하는데, 그 값은 합한 결과를 약분한 1/20이다.

using r1 = ratio<1, 60>;
using r2 = ratio<1, 30>;
using result = ratio_add<r1, r2>::type;

C++ 표준은 ratio 비교 연산 템플릿(ratio_equal, ratio_not_equal, ratio_less, ratio_less_equal, ratio_greater, ratio_greater_equal)도 제공한다. 산술 ratio 템플릿과 마찬가지로 ratio 비교 연산 템플릿도 컴파일 시간에 처리된다.

이런 비교 연산 템플릿은 결과를 표현하는 std::bool_constant란 타입을 새로 정의한다. bool_constant는 타입과 컴파일 시간 상숫값을 저장하는 struct 템플릿인 std::integral_constant 중 하나다. 예컨대 integral_constant<int, 15>는 15라는 정숫값을 저장한다.

bool_constant는 bool 타입에 대한 integral_constant이다. 예컨대 bool_constant<true>는 true라는 부울 타입 값을 저장하는 integral_constant<bool, true>다. ratio 비교 연산 템플릿 결과는 bool_constant<true>나 bool_constant<false> 중 하나가 된다. bool_constant나 integral_constant에 대한 값은 value라는 데이터 멤버로 접근 할 수 있다.