cvičení
zápočtové testy
zápočtové programy
můžeme používat překladače ve Visual Studiu
ve VS Code
dá se nainstalovat microsoftí překladač nebo gcc nebo clang ve verzi pro windows
na Windows bychom měli programy psát tak, aby fungovaly i na Linuxu
na grafické rozhraní knihovna Qt
budou po nás chtít překlad bez warningů
je dobré z programů vracet nulu
argv
vector
std::vector<std::string> arg(argv, argv + argc);argv a argv+argc jsou iterátorystd::string má konverzní konstruktor, z typu char* vznikne std::stringstd::vector<std::string> je kontejner stringůstringy
int main(int argc, char** argv) {
std::vector<std::string> arg(argv, argv + argc);
for (int i = 0; i < argc; ++i) {
// tohle nebude fungovat, protože arg[i] neopovídá typu %s
std::printf("%d: %s\n", i, arg[i]);
}
return 0;
}
aliasy typů pomocí using, používá se předpona t_
using t_arg = std::vector<std::string>;
for (auto&& x : parg)
třída std::ifstream … vstupní souborový stream
ctd::cout je typu std::ofstreamfstream umí vstup i výstupu, ale ovládá se komplikovanějistrstream, který pracuje s proměnnou typu stringdebug režim
starší funkce ze standardní knihovny nevypouštějí výjimky
ifstream nepovede otevřít, nastaví se chybový příznakfail() vrací true, pokud se poslední volání rozbilogood() vrací true, pokud je objekt v pořádkupříznak eof se nastaví až po tom, co se pokusíme přečíst data za koncem souboru
takže po každém čtení kontrolujeme fail, pokud to zfailovalo a nastavil se příznak eof, je to v pohodě – jsme na konci souboru
zajímavé věci, které můžeme použít
std::runtime_error, nepoužívá se newstd::sort k tříděnístd::pair se umí řadit lexikografickysize_tint budeme používat málokdy – většinou řešíme nějaké pozice, indexování do polestd::emplace_back na přidání dvojice na konec kontejneru dvojicstd::iotačasté chyby a poznámky
constexpr by se v hlavičkovém souboru mělo napsat inlineconstexpr je informace pro překladač, const je informace pro vývojářeconst, pokud nemodifikují své parametrystd::string& (nikoliv const) nemůžeme zavolat se zřetězením stringůusing konstrukci*std::string out;std::string out = "";std::string out(); nebo std::string out{};optional<T>optional<string> x; je automaticky inicializovaná jako neplatná!x, který nám řekne, že je nevalidní*x nebo x->vyhodnocování výrazů
poznámky
&s_ = &p;parser(istream & p) : s_(p) {}s_rozdělit projekt parseru do více „modulů“ (postaru)
impl nebo detailstrom výrazu
std::variant, ale to se tady moc nehodístd::unique_ptrOOP
virtualvirtual val_t eval(val_t x) const = 0;virtual void print(std::ostream& out) const = 0;class PlusNode : public AbstractNode {virtual val_t eval(val_t x) const override {using owner_ptr_t = std::unique_ptr<AbstractNode>;owner_ptr_t left_, right_;&&PlusNode(owner_ptr_t&& left, owner_ptr_t&& right) : left_(std::move(left)), right_(std::move(right)) {}using namespace std;using std::make_unique;alternativní úloha
y=1+2*x; x=y+1; se obvykle řeší pomocí nějaké mezikódu (bytecode)CONST 1CONST 2LD xMULADDST yLD yCONST 1ADDST xGOTO -10virtual void exec(double x, stack& s) const = 0;<algorithm>result.insert(result.end(), right.size(), nullptr);std::move(right.begin(), right.end(), result.end()-right.size());std::numeric_limits<T>
lowest … vrací minimummin … pro desetinná čísla vrací „epsilon“ (nejmenší kladnou hodnotu), jinak také minimummax … vrací maximumstd::plus a podobné objekty
template<typename OP>
class binary : public abstop {
public:
binary(.... l, .... r) : left(std::move(l)), right(std::move(r)) {}
virtual int eval() const override {
return f(left->eval(), right->eval())
}
private:
..... left, right, OP f;
}
taky by tam mohlo být třeba return OP()(left->eval(), right->eval());
nebo by první závorky mohly být složené
jak udělat genericky i typ, co vrací eval?
jak to udělat, abychom nemuseli mít int v typech uvedený dvakrát (jednou pro eval, jednou v rámci plus)?
// chceme použít
binary<plus<int>>
// uvnitř bude
using my_type = typename OP::result_type; // nefunguje v C++20
// nebo
// chceme použít
binary<int, plus>
// to se dělá takhle
template<typename my_type, template<typename> typename GOP>
class binary : public abstrop<my_type> {
using OP = GOP<my_type>;
}
naše mainy mají vracet nulu, jinak s tím recodex bude mít problém
je dobré ty řádky udělat tak, aby se daly iterovat třeba pomocí dvojtečkového for cyklu
a.rows() by mohla vracet řádky matice.cols() sloupcematice by měla být šablona
ale zatím asi psát bez šablon
lze implementovat pomocí vektoru vektorů
lze implementovat pomocí jednoho vektoru
row_iterator)class row_iterator {
public:
row_iterator &operator ++() {
// něco
return *this;
}
// tohle je prefixový ++
// kdybychom chtěli postfixový, bylo by to s jedním intovým parametrem
// (žádný intový argument se nepředává)
// a musíme vracet hodnotou
row_iterator operator ++(int) {
row_iterator tmp = *this;
++*this;
return tmp;
}
row_ref operator *() const { /* ... */ }
// trikové řešení: do iterátoru zavřu row_ref
// obvykle se z operátoru hvězdičky vrací T&
}
bool operator !=(const row_iterator& a, const row_iterator& b) { /* ... */ }
// můžeme implementovat spaceship operator
iterátory pro prvky řádku už můžou být přímo C pointery
C pointery mají vlastnosti iterátorů
co potřebujeme
rows_t*((*(a.rows().begin())).begin()) … takhle se dostanu k levému hornímu prvku maticezápočtový test
úloha
co když chytám do proměnné typu auto&& návratovou hodnotu funkce a funkce mi vrátí hodnotou?
každý kontejner má v sobě definovat typ iterator
každý iterátor má v sobě definovat typ reference
typename
std::vector<T>::iteratorkdyž podporujeme hvězdičku, měli bychom podporovat šipku
typické chyby
1+2++ se přečte jako 1+2+0+0 (mělo by to vrátit chybu)poznámky
[[nodiscard]] (pak by překladač měl ječet, pokud nečteme návratovou hodnotu funkce)map<string, size_t> m;
if (m.exists(ident)) {
id = m[ident];
// neefektivní řešení, v mapě vyhledávám dvakrát
} else {
m[ident] = id = m.size();
}
lepší je použít m.find, to vrátí iterátor it
it->secondjak to udělat správně?
id = m.size();
auto [it, b] = m.emplace(ident, id);
if (!b) {
id = it->second;
}
// b je true, pokud tam ten prvek ještě nebyl
// když se emplace nepovedl, tak je b false a iterátor míří na překážející prvek
další varianta: try_emplace
výhodnější – nevytváří objekt, dokud není jasné, že tam půjde vložit
úloha index_map
.data je logický ekvivalent .c_strset<size_t>?set<size_t, my_cmp>, pomocí vlastního komparátoru (ten se bude dívat do vektoru) budeme porovnávat číslanaše řešení můžeme vylepšovat až do okamžiku před testem
deadline je měkký – můžeme submitovat i potom
příklad: telefonní seznam
retset find_by_prefix(const string& pref)void set_phone_number(…)orientovaný graf