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::string
std::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::ofstream
fstream
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 new
std::sort
k tříděnístd::pair
se umí řadit lexikografickysize_t
int
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 inline
constexpr
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 detail
strom výrazu
std::variant
, ale to se tady moc nehodístd::unique_ptr
OOP
virtual
virtual 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 1
CONST 2
LD x
MUL
ADD
ST y
LD y
CONST 1
ADD
ST x
GOTO -10
virtual 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>::iterator
když 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->second
jak 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_str
set<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