relaciones programacion orientada objetos entre ejemplos diagrama composicion codigo clases asociacion agregacion c++ c++11 chrono

c++ - programacion - ¿Cuál es la mejor manera de formar relaciones estándar std:: chrono:: durations and std::?



relaciones entre clases programacion orientada a objetos (1)

Estaba leyendo esta excelente respuesta que usaba las microfortnights unidad de duración del tiempo cómico para ilustrar un buen punto de una manera memorable.

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

Y se me ocurrió la pregunta:

Si realmente quisiera hacer esto (lo más probable es que tenga alguna otra duración no trivial, como el tiempo disponible durante un cuadro o durante los N ciclos de un procesador), ¿cuál es la mejor manera de hacerlo?

Sé que la ratio<N, D> creará un tipo único asociado con cada valor de N y D Por lo tanto, la ratio<4, 6> es un tipo diferente que la ratio<2, 3> , aunque representan la misma fracción (reducida). ¿Siempre tengo que hacer los cálculos para simplificar el factor de conversión a términos reducidos?

Sería más conveniente escribir:

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

en lugar de:

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

Pero entonces estos serían dos tipos diferentes, en lugar del mismo tipo. La primera expresión es más fácil de inspeccionar para la corrección. Pero hay muchas representaciones de esta fracción, y la segunda es posiblemente canónica, y por lo tanto preferida. Si tengo demasiados tipos vagando por mi programa que en realidad representan la misma unidad, entonces eso puede llevar a un aumento innecesario del código de la plantilla.


A continuación, estoy ignorando los espacios de nombres con el interés de ser conciso. duration está en el espacio de nombres std::chrono , y la ratio está en el espacio de nombres std .

Hay dos buenas maneras de asegurarse siempre de que su ratio se reduzca a los términos más bajos sin tener que hacer la aritmética. El primero es bastante directo:

La formulacion directa

Si solo quiere saltar directamente a las microfortnights , pero sin tener que darse cuenta de que la fracción reducida de 86,400 * 14 / 1,000,000 es 756/625, simplemente agregue ::type después de la ratio :

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

El type anidado de cada ratio<N, D> es otra ratio<Nr, Dr> donde Nr/Dr es la fracción reducida N/D Si N/D ya está reducido, entonces la ratio<N, D>::type es del mismo tipo que la ratio<N, D> . De hecho, si ya hubiera descubierto que 756/625 era la fracción reducida correcta, pero era paranoico al pensar que podría reducirse aún más, podría haber escrito:

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

Entonces, si tiene alguna duda de que su ratio se expresa en los términos más bajos, o simplemente no quiere que le molesten con la verificación, siempre puede agregar el ::type a su tipo de ratio para estar seguro.

La formulación verbosa.

Las unidades de duración de tiempo personalizadas a menudo aparecen como parte de una familia. Y a menudo es conveniente tener toda la familia disponible para su código. Por ejemplo, las microfortnights están obviamente relacionadas con fortnights , que a su vez están relacionadas con weeks , que se derivan de days , que se derivan de hours (o de seconds si lo prefiere).

Al construir a su familia una unidad a la vez, no solo hace que toda la familia esté disponible, sino que también reduce la posibilidad de errores al relacionar a un miembro de la familia con otro con la conversión más simple posible. Además, hacer uso de std::ratio_multiply y std::ratio_divide , en lugar de multiplicar los literales también significa que no tiene que mantener insert ::type todas partes para asegurarse de mantener su ratio en los términos más bajos.

Por ejemplo:

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

ratio_multiply es un nombre typedef al resultado de la multiplicación ya reducida a los términos más bajos. Así que lo anterior es exactamente el mismo tipo que:

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

Incluso puede tener ambas definiciones en la misma unidad de traducción, y no obtendrá un error de redefinición. En cualquier caso, ahora puedes decir:

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>>;

Y hemos terminado con un nombre de typedef para las microfortnights que es exactamente el mismo tipo que en nuestra formulación directa, pero a través de una serie de conversiones mucho más simples. Aún no tenemos que preocuparnos por reducir las fracciones a los términos más bajos, y ahora tenemos varias unidades útiles en lugar de solo una.

También tenga en cuenta el uso de std::micro en lugar de std::ratio<1, 1000000> . Este es otro lugar para evitar errores por descuido. Es tan fácil (al menos para mí) confundir (y leer mal) el número de ceros.