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 TValue je 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 TUnit i TValue.

  • Násobit a dělit je možné libovolné instance se stejným typem TValue.

    • Násobek dvou instancí má TUnit typu multiplied_unit<TUnit1, TUnit2>.

    • Podíl dvou instancí má TUnit typu divided_unit<TUnit1, TUnit2>.

Tipy

  • Argument TPowers šablony unit representuje "vektor" exponentů. Pro tento účel lze použít std::integer_sequence<int, /*...*/>.

  • Při implementaci basic_unit bude pravděpodobně nutné explicitně přetypovat konstanty Index a TEnum::_count na int.

  • Šablona std::make_integer_sequence může být užitežná při implemntaci basic_unit.

  • Jediné místo, kde je rekurze opravdu nutná, je případ multiplied_unit se 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.