2015-01-10 15 views
27

Tôi đã đọc this excellent answer sử dụng đơn vị thời lượng hài hước microfortnights để minh họa cho một điểm tốt một cách đáng nhớ.Cách tốt nhất để tạo thành std :: chrono :: durations và std :: ratios là gì?

typedef std::ratio<756, 625> microfortnights; 
std::chrono::duration<int, microfortnights> two_weeks(1000000); 

Và câu hỏi xảy ra với tôi:

Nếu tôi thực sự muốn làm điều này (nhiều khả năng một số không tầm thường thời gian khác như thời gian có sẵn trong một khung hình, hoặc trong N chu kỳ của một bộ xử lý), cách tốt nhất để làm điều này là gì?

Tôi biết ratio<N, D> sẽ tạo loại duy nhất được liên kết với mỗi giá trị ND. Vì vậy, ratio<4, 6> là một loại khác với ratio<2, 3>, mặc dù chúng đại diện cho cùng một (giảm) phần. Tôi có luôn luôn phải làm toán để đơn giản hóa các yếu tố chuyển đổi để giảm các điều khoản?

Nó sẽ là thuận tiện hơn để viết:

using microfortnights = std::chrono::duration<long, ratio<86400*14, 1000000>>; 

thay vì:

using microfortnights = std::chrono::duration<long, ratio<756, 625>>; 

Nhưng sau đó những sẽ là hai loại khác nhau, thay vì cùng loại. Biểu thức đầu tiên là dễ dàng hơn để kiểm tra tính chính xác. Nhưng có nhiều biểu diễn của phân số này, và phần thứ hai được cho là kinh điển, và do đó được ưa thích. Nếu tôi có quá nhiều loại lang thang xung quanh chương trình của tôi mà thực sự đại diện cho cùng một đơn vị, sau đó có thể dẫn đến bloat mã mẫu không cần thiết.

+1

Bạn có thể thay đổi cụm từ câu hỏi thành 'std :: ratio' thay thế không? Dường như chủ đề bao quát có rất ít việc phải làm với 'chrono' ngoại trừ ví dụ đã chọn? – sehe

+0

Bạn có một điểm tốt. Tuy nhiên tôi muốn tập trung vào 'thời lượng', nếu không tôi sợ khán giả sẽ không thấy ứng dụng thực tế của 'tỷ lệ'. Tôi đã thêm 'tỷ lệ' vào tiêu đề để các tìm kiếm cho' tỷ lệ' sẽ dễ dàng tìm thấy Q/A này hơn. –

+0

Hehe. 1 cho anyways thiết lập. (Trớ trêu thay, phải mất một thời gian để thấy rằng điều này thực sự có liên quan hơn là chỉ để tạo ra _microfortnight_ khó hiểu "đúng" :)) – sehe

Trả lời

29

Dưới đây tôi bỏ qua các không gian tên vì lợi ích của việc súc tích. duration nằm trong không gian tên std::chronoratio nằm trong không gian tên std.

Có hai cách tốt để luôn đảm bảo rằng ratio của bạn được giảm xuống các điều kiện thấp nhất mà không phải tự mình làm số học. Đầu tiên là khá trực tiếp:

Việc xây dựng trực tiếp

Nếu bạn chỉ muốn nhảy thẳng đến microfortnights, nhưng mà không cần phải tìm ra rằng phần giảm 86.400 * 14/1.000.000 là 756/625, chỉ cần thêm ::type sau ratio:

using microfortnights = duration<long, ratio<86400*14, 1000000>::type>; 

các lồng nhau type của mỗi ratio<N, D> là một ratio<Nr, Dr> nơi Nr/Dr là giảm phần N/D. Nếu N/D đã bị giảm, thì ratio<N, D>::type là cùng loại với ratio<N, D>.Trên thực tế, đã có tôi đã tìm ra rằng 756/625 là giảm phần đúng, nhưng chỉ là hoang tưởng trong suy nghĩ nó có thể có thể giảm hơn nữa, tôi có thể viết:

using microfortnights = duration<long, ratio<756, 625>::type>; 

Vì vậy, nếu bạn có bất kỳ nghi ngờ rằng bạn ratio được thể hiện bằng thuật ngữ thấp nhất hoặc không muốn bị làm phiền với việc kiểm tra, bạn luôn có thể thêm ::type vào loại ratio của mình để đảm bảo.

Việc xây dựng verbose

đơn vị thời gian thời gian Tuỳ chỉnh thường bật lên như là một phần của một gia đình. Và nó thường thuận tiện để có toàn bộ gia đình có sẵn cho mã của bạn. Ví dụ: microfortnights rõ ràng là liên quan đến fortnights, lần lượt có liên quan đến weeks, có nguồn gốc từ days, có nguồn gốc từ hours (hoặc từ seconds nếu bạn thích).

Bằng cách xây dựng một gia đình mỗi lần, bạn không chỉ làm cho toàn bộ gia đình có sẵn, bạn cũng giảm nguy cơ lỗi bằng cách liên kết một thành viên gia đình với thành viên khác với chuyển đổi đơn giản nhất có thể. Ngoài ra, việc sử dụng std::ratio_multiplystd::ratio_divide, thay vì nhân chữ cái cũng có nghĩa là bạn không phải giữ thêm ::type ở khắp mọi nơi để đảm bảo rằng bạn giữ số ratio ở mức thấp nhất.

Ví dụ:

using days = duration<long, ratio_multiply<hours::period, ratio<24>>>; 

ratio_multiply là một typedef tên đến kết quả của phép nhân đã giảm xuống còn từ ngữ thấp nhất. Vì vậy, ở trên là chính xác cùng loại như:

using days = duration<long, ratio<86400>>; 

Bạn thậm chí có thể có cả hai định nghĩa trong các đơn vị dịch tương tự, và bạn sẽ không nhận được một lỗi tái định nghĩa. Trong mọi trường hợp, bây giờ bạn có thể nói:

using weeks   = duration<long, ratio_multiply<days::period,  ratio<7>>>; 
using fortnights  = duration<long, ratio_multiply<weeks::period,  ratio<2>>>; 
using microfortnights = duration<long, ratio_multiply<fortnights::period, micro>>; 

Và chúng tôi đã kết thúc với một typedef tên cho microfortnights đó là chính xác cùng loại như trong xây dựng trực tiếp của chúng tôi, nhưng qua một loạt các đơn giản hơn nhiều chuyển đổi. Chúng tôi vẫn không phải bận tâm với việc giảm phân số xuống các điều kiện thấp nhất, và bây giờ chúng tôi có một số đơn vị hữu ích thay vì chỉ một.

Cũng lưu ý việc sử dụng std::micro thay cho std::ratio<1, 1000000>. Đây là một nơi khác để tránh các lỗi bất cẩn. Nó rất dễ dàng (ít nhất là đối với tôi) để nhập nhầm (và đọc sai) số lượng số 0.

Các vấn đề liên quan