C++ typ interval

C++ typ interval
« kdy: 08. 08. 2020, 19:08:54 »
Dobrý deň, dala by sa v C++ napísať šablóna, ktorá by do základného typu povolila zádávať literály v intervale od do? Ide mi len o compile type kontrolu, runtime si spravím aj sám, ale bolo by pekné keby mi zadávanie (ne)správneho čísla odhalil už compiler / editor.

Typ interval mal aj pascal a delphi. Napr:

Kód: [Vybrat]
type
    SmallLatinLetters: 'a'..'z';
    Hours: 1..12;
    Minutes: 0..59;
    Byte: 0..255;

No a ja by som chcel template, ktorý by zabezpečil podobnú funkcionalitu aj v C++ a mohol by fungovať nejako takto:
Kód: [Vybrat]
typedef interval<int, 1, 12> hours;
hours a = 1; // ok
a = 5; // ok
a = 12; // ok
hours b = 13; // chyba
hours c = 0; //chyba
a = 15; //chyba


Re:C++ typ interval
« Odpověď #1 kdy: 08. 08. 2020, 19:18:38 »
A jak si představuješ, že by to mělo řešit ty skutečně zajímavé situace jako

Kód: [Vybrat]
hours foo = bar()

?

bar() je v jiném souboru. A výsledek závisí na I/O.

Re:C++ typ interval
« Odpověď #2 kdy: 08. 08. 2020, 20:37:43 »
A jak si představuješ, že by to mělo řešit ty skutečně zajímavé situace jako

Kód: [Vybrat]
hours foo = bar()

?

bar() je v jiném souboru. A výsledek závisí na I/O.

To by bola iba compile-time kontrola. Runtime checky tam nechcem tie si viem spraviť pomocou if-u a len tam kde ich naozaj potrebujem, keby boli runtime checky všade kde sa inicializuje, priraduje, alebo mení hodnota, tak by to zbytočne spomalovalo beh programu a to neni žiaduce.

Ale bolo by pekné aspoň to, keby ťa compiler, resp šikovné IDE v compile time upozornilo, že tam nemáš dávať nesprávny literál. Bola by to pomôcka pre programátorov. Kontextová nápoveda by ti tam zobrazila číslo od-do, aké tam môžeš priradiť. A ak by si tam priradil nesprávny literál, tak by ti to editor podčiarkol trebárs červenoou farbou, ako chybu, alebo by ti tú chybu vypísal kompilátor.

POZN: Vylepšená verzia by mohla robiť v debug móde aj runtime checking, ale release móde by sa takéto kontroly vypli kôli rýchlosti - ale to už by bolo pomocou šablón moc zložité.  Tak to fungovalo mimochodom aj v pascale a delphi pri type interval a tuším že ADA to tak má tiež.

V Pascale ak sa nezapli nejaké runtime checky to fungovalo nasledovne:

Kód: [Vybrat]
var
   a: 0..23;
begin
   a := 20; //ok
   a := 23; //ok
   a := a + 1; // ok aj keď číslo je mimo intervalu
   a := 24; // chyba
« Poslední změna: 08. 08. 2020, 20:42:22 od fortran1986 »

alex6bbc

  • *****
  • 1 432
    • Zobrazit profil
    • E-mail
Re:C++ typ interval
« Odpověď #3 kdy: 08. 08. 2020, 21:14:48 »
jednoduchy pokus:

#include <iostream>

template <typename T, int MIN, int MAX>
class Interval
{
public:

Interval() : value(MIN+1) {}
Interval(T x) : value(x) {}
Interval(T& x) : value(x) {}

void print() { std::cout << "I:" << value << std::endl; }

Interval& operator=(T& other)
{
 if (other < MIN || other > MAX)
     std::cout << "MIN,MAX ERROR!" << std::endl;
 else
     value = other;

 return *this;
}

Interval operator=(T other)
{
 if (other < MIN || other > MAX)
     std::cout << "MIN,MAX ERROR!" << std::endl;
 else
     value = other;

 return *this;
}


private:

T value;

};

//-----------------------------------------------------------

int main()
{
Interval <int, 0, 5> x;
x.print();

x=3;
x.print();

x=22;
x.print();


return 0;
}

alex6bbc

  • *****
  • 1 432
    • Zobrazit profil
    • E-mail
Re:C++ typ interval
« Odpověď #4 kdy: 08. 08. 2020, 21:15:58 »
v parametrech template lze myslim pouzivat jen int, nikoliv double, float.
takze s tim bude problem.
a samozrejme by to chtelo testy pro neciselne/necelociselne typy.

https://en.cppreference.com/w/cpp/types/is_integral
« Poslední změna: 08. 08. 2020, 21:18:39 od alex6bbc »


Re:C++ typ interval
« Odpověď #5 kdy: 09. 08. 2020, 03:06:32 »
jednoduchy pokus:

#include <iostream>

template <typename T, int MIN, int MAX>
class Interval
{
public:
...

Wow, veľmi ti ďakujem :) ráno to vyskúšam.. Diky.

tecka

  • ***
  • 138
    • Zobrazit profil
    • E-mail
Re:C++ typ interval
« Odpověď #6 kdy: 09. 08. 2020, 17:04:14 »
To by bola iba compile-time kontrola. Runtime checky tam nechcem tie si viem spraviť pomocou if-u a len tam kde ich naozaj potrebujem, keby boli runtime checky všade kde sa inicializuje, priraduje, alebo mení hodnota, tak by to zbytočne spomalovalo beh programu a to neni žiaduce.

Kdybys napsal, že si jen tak hraješ, tak budiž, ale ty napíšeš takový nesmysl.

Wow, veľmi ti ďakujem :) ráno to vyskúšam.. Diky.

To je runtime test a měl bys to vidět na první pohled.

Re:C++ typ interval
« Odpověď #7 kdy: 09. 08. 2020, 21:35:39 »
Pozri na implementáciu std::array, tam by mala byť compile time kontrola na index do poľa pri operátore []

Re:C++ typ interval
« Odpověď #8 kdy: 09. 08. 2020, 22:22:59 »
...

Sorry, ale neni to to čo som hľadal. Včera o 3tej ráno som to už nepozeral, ale ja som hľadal compile-time kontrolu.

Kdybys napsal, že si jen tak hraješ, tak budiž, ale ty napíšeš takový nesmysl.

To je runtime test a měl bys to vidět na první pohled.

Možno by nezaškodilo pridať sem nejaké hodnotenie odpovedí ako na stackoverflow. Niektoré odpovede nemajú fakt žiadnu hodnotu. A potom tu vznikajú nekonečné flame wars o úplných malichernostiach.

Pozri na implementáciu std::array, tam by mala byť compile time kontrola na index do poľa pri operátore []

diky pozriem :)

Re:C++ typ interval
« Odpověď #9 kdy: 09. 08. 2020, 22:56:46 »
Jako cvičení to může být zajímavé, ale neřeší to nic.

Re:C++ typ interval
« Odpověď #10 kdy: 09. 08. 2020, 23:30:34 »
Jako cvičení to může být zajímavé, ale neřeší to nic.

Je to pomôcka. Pozrite si taký typescript, všetky types a interfaces  - všetko sa checkuje len v compile time, samotné behové prostredie javascriptu tie typy nepozná a v runtime sú tie typy teda úplne zbytočné. A ajtak ich používanie programátorom veľmi ulahčuje život a sú ochotní si tie classy a metódy otypovať aj keď je to práca navyše.

Kompilátor odhalí kopu chýb a editor ich používa ako metadáta aby vám zobrazil informáciu o tom parametre a nedovolí vám tam vložiť nesprávny literál. Už len to keď viete že môžete vložiť číslo od do je často veľká pomôcka. V dokumentácii sa také niečo stratí. Síce to neni 100ne nepriestrelné riešenie, ale je to riešenie v rámci možností.

Nevýhoda je, že to môže dať programátorovi pocit falošného bezpečia - všetko má svoje pre a proti.

Idris

  • *****
  • 2 286
    • Zobrazit profil
    • E-mail
Re:C++ typ interval
« Odpověď #11 kdy: 10. 08. 2020, 00:18:04 »
Jako cvičení to může být zajímavé, ale neřeší to nic.
Je to pomôcka. Pozrite si taký typescript, všetky types a interfaces  - všetko sa checkuje len v compile time, samotné behové prostredie javascriptu tie typy nepozná a v runtime sú tie typy teda úplne zbytočné. A ajtak ich používanie programátorom veľmi ulahčuje život a sú ochotní si tie classy a metódy otypovať aj keď je to práca navyše.

Kompilátor odhalí kopu chýb a editor ich používa ako metadáta aby vám zobrazil informáciu o tom parametre a nedovolí vám tam vložiť nesprávny literál. Už len to keď viete že môžete vložiť číslo od do je často veľká pomôcka. V dokumentácii sa také niečo stratí. Síce to neni 100ne nepriestrelné riešenie, ale je to riešenie v rámci možností.

Nevýhoda je, že to môže dať programátorovi pocit falošného bezpečia - všetko má svoje pre a proti.
V C++ jdou sice podobné věci přes šablony (a constexpr), ale jen pro konstanty a bůhvíjaká krása ten zápis taky není. Je poučné podívat se na jazyky, které mají takzvané závislostní typy, ty umožňují kontrolovat hodnoty (například meze intervalu) během překladu, i když nejde o konstanty.

Re:C++ typ interval
« Odpověď #12 kdy: 10. 08. 2020, 06:50:03 »
Jako cvičení to může být zajímavé, ale neřeší to nic.
Je to pomôcka. Pozrite si taký typescript, všetky types a interfaces  - všetko sa checkuje len v compile time, samotné behové prostredie javascriptu tie typy nepozná a v runtime sú tie typy teda úplne zbytočné. A ajtak ich používanie programátorom veľmi ulahčuje život a sú ochotní si tie classy a metódy otypovať aj keď je to práca navyše.

Kompilátor odhalí kopu chýb a editor ich používa ako metadáta aby vám zobrazil informáciu o tom parametre a nedovolí vám tam vložiť nesprávny literál. Už len to keď viete že môžete vložiť číslo od do je často veľká pomôcka. V dokumentácii sa také niečo stratí. Síce to neni 100ne nepriestrelné riešenie, ale je to riešenie v rámci možností.

Nevýhoda je, že to môže dať programátorovi pocit falošného bezpečia - všetko má svoje pre a proti.
V C++ jdou sice podobné věci přes šablony (a constexpr), ale jen pro konstanty a bůhvíjaká krása ten zápis taky není. Je poučné podívat se na jazyky, které mají takzvané závislostní typy, ty umožňují kontrolovat hodnoty (například meze intervalu) během překladu, i když nejde o konstanty.

Tak, tak.

Kontrola v čase překladu je skvělá věc. Ale má to smysl, když hledá skutečné chyby, ne ten Fortranův příklad, kde při reálném programování problém nebude.

JaaSt

Re:C++ typ interval
« Odpověď #13 kdy: 10. 08. 2020, 08:32:48 »
Sice si neumím představit reálné využití, ale když už bych něco takového potřeboval, hodil bych si to na makra.

#if DEBUG
#define TEST(x) ( kód obsahující static_assert )
#else
#define TEST(x) (x)
#endif

Pak by přiřazení vypadalo takhle:

int x = TEST(12)

static_assert by se použilo podle konkrétní potřeby (nechce se mi to psát)

v Debug by se prováděl test a v Release ne.


Re:C++ typ interval
« Odpověď #14 kdy: 10. 08. 2020, 09:58:30 »
Před časem jsem si s něčím podobným hrál. Povedlo se mi to jenom částečně. Jestli ten výsledek stojí za to je těžko říct.

S kontrolou přiřazení je problém ten, že překladač udělá z literálu normální int dřív než se k němu rozumně dostaneš. Takže z toho literálu musíš udělat něco jako std::integral_constant. Asi nejrozumněji vypadající inicializace bude:
Kód: [Vybrat]
hours = lit<13>();
hours = 13_ic;
Pro druhou verzi bylo třeba si napsat vlastní uživatelsky definovaný literál. Znamená to si napsat parser intů přes šablony. IMO to za to vážně nestojí. Na první verzi stačí:
Kód: [Vybrat]
template<intmax_t I> struct lit : std::integral_constant<intmax_t, I> {};
Pak už může mít ten interval šablonový konstruktor co bere integral_constant a v něm se dá použít ten static_assert.

Co jsem nakonec dotáhl do použitelného stavu nebyly plnotučné intervaly ale jen otypované indexy a velikosti.
  • Rozsahy se kontrolují assertem v runtime. Ale ve chvíli kdy se udělal z intu index, tak žádné další asserty nebyly.
  • Kromě maximální velikosti měly ty indexy i tag. Takže prohození indexů jablek a hrušek se při kompilaci chytlo.
  • Hlavně jsem tím vychytal automatické konverze intů. Index se dal převést na libovolný integer, ale static_assert hlídal jestli se tam vleze. A taky jsem tím zatrhl Cčkovou past kdy "( uint <= -1 ) == true"

Hlavně tyhle hrátky ber jako druh intelektuální masturbace a ne jako něco, co se od tebe čeká. Spíš se nauč pracovat s nějakým statickým analyzátorem. S ním dostaneš daleko víc muziky za míň peněz.