Fórum Root.cz
Hlavní témata => Vývoj => Téma založeno: fortran1986 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:
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:
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
-
A jak si představuješ, že by to mělo řešit ty skutečně zajímavé situace jako
hours foo = bar()
?
bar() je v jiném souboru. A výsledek závisí na I/O.
-
A jak si představuješ, že by to mělo řešit ty skutečně zajímavé situace jako
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:
var
a: 0..23;
begin
a := 20; //ok
a := 23; //ok
a := a + 1; // ok aj keď číslo je mimo intervalu
a := 24; // chyba
-
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;
}
-
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
-
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.
-
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.
-
Pozri na implementáciu std::array, tam by mala byť compile time kontrola na index do poľa pri operátore []
-
...
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 :)
-
Jako cvičení to může být zajímavé, ale neřeší to nic.
-
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.
-
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.
-
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.
-
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.
-
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:
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čí:
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.
-
v Debug by se prováděl test a v Release ne.
A není to jedno, když je to static_assert? Rozlišení debug/release je záležitost runtimu.