Zkouška C++ 24. 6. 2026
Idea
Při práci s fyzikálními veličinami nás často nezajímá jen hodnota každé proměnné, ale i o kterou veličinu se jedná a jakou má jednotku. Např. proměnná obsahující rychlost může nabývat hodnotu v = 7 660 m/s. Cílem úlohy je umožnit vývojářům použít pomocné typy, které tuto informaci u proměnných umožňují uchovat. Kompilátor nesmí umožnit přiřazení, sčítání či odčítání dvou proměnných různých jednotek a zároveň musí být schopen odvodit jednotku násobku či podílu dvou proměnných.
Nebudete vytvářet systém pro konkrétní soustavu jednotek, ale obecnou sadu šablon, nad kterou si bude moci uživatel svou vlastní soustavu jednotek, např. SI. V takovém systemu jsou:
Základní jednotky, např. m, kg, s.
Odvozená jednotky, např. m/s, N = kg.m.s⁻².
Libovolnou jednotku lze vyjádřit pomocí celočíselných exponentů základních jednotek. Např. v SI máme 7 základních jednotek:
[s, m, kg, A, K, mol, cd]
Čas v sekundách lze reprezentovat jako vektor:
[1, 0, 0, 0, 0, 0, 0]
Sílu v N = kg.m.s⁻² jako:
[-2, 1, 1, 0, 0, 0, 0]
Pokud násobíte hodnoty se dvěma různými jednotkami, jednotku jejich násobku získáte součtem těchto vektorů, jednotku podílu hodnot pak rozdílem jejich vektorů.
Použití
#include "units.hpp" #include <iostream> enum class si_units { second, metre, kilogram, ampere, kelvin, mole, candela, _count }; using second = basic_unit<si_units, si_units::second>; using metre = basic_unit<si_units, si_units::metre>; using kilogram = basic_unit<si_units, si_units::kilogram>; using metre_per_second = divided_unit<metre, second>; using newton = divided_unit<multiplied_unit<kilogram, metre>, multiplied_unit<second, second>>; int main() { quantity<metre> l(2.1); quantity<second> t(0.9); auto v1(l / t); quantity<metre_per_second> v2{ 2.5 }; std::cout << (v1 + v2).value() << std::endl; // Won't compile //std::cout << (l + t).value() << std::endl; }
Rozhraní
TEnum
Tento typ uvedený v šablonách níže je enum dodaný uživatelem, který obsahuje základní jednotky pro danou soustavu (předpokládáme fyzikální, ale lze využít i třeba pro finančnictví). TEnum musí obsahovat položku _count, která není fyzikální jednotkou sama o sobě, ale obsahuje počet prvků v enumu (nejlepší je ji přidat jako jeho poslední položku, jak je vidět v příkladu výše).
template <typename TEnum, typename TPowers> struct unit;
Pomocná "tagová" šablona obsahující enum, který určuje množinu základních jednotek, a statický vektor exponentů těchto jednotek.
template <typename TEnum, TEnum Index> using basic_unit = ...
Typová definice, která vytvoří typ unit na základě určené soustavy jednotek a konkrétní vybrané základní jednotky. Statický vektor bude mít délku TEnum::_count, na indexu Index bude obsahovat 1 a na ostatních místech 0.
template <typename TFirstUnit, typename ... TOtherUnits> using multiplied_unit = ...
Typová definice, která vytvoří typ unit nad danou soustavou jednotek, výsledný vektor bude obsahovat součet vektorů všech zadaných jednotek.
template <typename TDividendUnit, typename TDivisorUnit> using divided_unit = ...
Typová definice, která vytvoří typ unit nad danou soustavou jednotek, výsledný vektor bude obsahovat rozdíl vektorů zadaných jednotek.
template <typename TUnit, typename TValue = double> struct quantity;
Struktura pro uchování hodnoty typu TValue s jednotkou (typu unit) TUnit. Nároky:
Z hodnoty typu
TValueje možné ji vytvořit jen explicitně, tj. není možné do ní omylem přiřadit hodnotu bez jednotky.Pomocí veřejné metody
value()je možné získat uloženou hodnotu.Sčítat a odečítat je možné pouze instance se stejným typem
TUnitiTValue.Násobit a dělit je možné libovolné instance se stejným typem
TValue.Násobek dvou instancí má
TUnittypumultiplied_unit<TUnit1, TUnit2>.Podíl dvou instancí má
TUnittypudivided_unit<TUnit1, TUnit2>.
Tipy
Argument
TPowersšablonyunitrepresentuje "vektor" exponentů. Pro tento účel lze použítstd::integer_sequence<int, /*...*/>.Při implementaci
basic_unitbude pravděpodobně nutné explicitně přetypovat konstantyIndexaTEnum::_countnaint.Šablona
std::make_integer_sequencemůže být užitežná při implemntacibasic_unit.Jediné místo, kde je rekurze opravdu nutná, je případ
multiplied_unitse třemi nebo více argumenty.V úloze je skryto několik problémů, které budou pravděpodobně vyžadovat parciální specializace šablon tříd/struktur.
K řešení úlohy stačí 100 řádek kódu.
Odevzdávání
Odevzdané řešení musí obsahovat soubor units.hpp.
nuance
We also gotten (?subset of) tests available in recodex to download, shortly after we started.
It was enough to submit only one header file with everything in it.