IT rekvalifikace s garancí práce. Seniorní programátoři vydělávají až 160 000 Kč/měsíc a rekvalifikace je prvním krokem. Zjisti, jak na to!
Hledáme nové posily do ITnetwork týmu. Podívej se na volné pozice a přidej se do nejagilnější firmy na trhu - Více informací.

Diskuze: Nahrazení auto statickým typem, aneb co to je sakra za typ?

V předchozím kvízu, Online test znalostí C++, jsme si ověřili nabyté zkušenosti z kurzu.

Aktivity
Avatar
Petr Čech
Tvůrce
Avatar
Petr Čech:30.3.2018 16:49

Ahoj, bohužel musím pracovat s jazykem, kde nelze ladit generiku (a vlastně ani nic jiného), pokud člověk na 100% neví, co dělá a já to bohužel nevím... (C++)

Mám template třídu, co se bude starat o rychlé hledání objektu podle alternativních klíčů:

template<class Tkey, class Tval>
class Index {
private:
    struct Pair {
        Pair(const Tkey &key, const Tval &value) :
                key(key), value(value) {}

        const Tkey &key;
        const Tval &value;

        bool operator<(const Pair &other) {
            return key < other.key;
        }

        bool operator==(const Pair &other) {
            return key == other.key;
        }
    };

    vector<Pair *> data;
public:
    /**
     * Adds a new pair to the index and sorts it.
     * @param key
     * @param value
     */
    void add(const Tkey &key, const Tval &value) {
        Pair *inserted = new Pair(key, value);

        auto iter = data.begin();
        auto last = data.end();
        for (; iter != last; ++iter) {
            if ((inserted->key < (*iter)->key)) {
                break;
            }
        }
        data.insert(iter, inserted);
    }

    /**
     * Finds the value corresponding to key with logarithmic complexity
     * @param key
     * @return
     * @throws NoDataException if not found
     */
    const Tval find(const Tkey &key) const {
        if (data.size() == 0) {
            throw NoDataException();
        }
        Pair *dummy = new Pair(key, data[0]->value);

        auto result = lower_bound(data.begin(), data.end(), dummy, [](const Pair *a, const Pair *b) {
            return a->key < b->key;
        });

        if (result == data.end()) {
            throw NoDataException();
        } else {
            return (*result)->value;
        }
    }
}

Jistě si všimnete, že by se mi ten iterátor result hodil i ve funkci add a potom i v remove (zatím není) a proto by bylo záhodno si to vytáhnout do funkce. Za 2 hodiny se mi ale nepodařilo přijít na to, co by mělo být jejím návratovým typem :( , poradí někdo? Teď tam prostě mám duplicity, protože jsem to vzdal a nemám nejmenší motivaci s tímto jazykem pracovat hezky.
Přesto mě zajímá, jak to je správně...

FAQ: je to úkol do školy, proto s tím musím dělat a proto nemůžu použít mapu...

Odpovědět
30.3.2018 16:49
the cake is a lie
Avatar
B42P6
Člen
Avatar
Odpovídá na Petr Čech
B42P6:30.3.2018 20:34

Ahoj, neviem či to máte povolené alebo nie, ale v C++14 môže byť aj návratový typ auto. A preto stačí v C++14 jednoducho:

const auto getIter(Pair *dummy)
        {
                return lower_bound(data.begin(), data.end(), dummy, [](const Pair *a, const Pair *b) {
            return a->key < b->key;
        });
    }

Ak ale musíš používať C++11, musíš zistiť aký typ vracia funkcia lower bound.

Návratovy typ je ForwardIt, čo je typ prvého argumentu.
V tvojom prípade to je data.begin(), čo je iterátor triedy std::vector.

Konkrétne je dátový typ iteratóra std::vector::i­terator. Výsledná funkcia vyzerá takto:

const typename vector<Pair *>::iterator getIter(Pair *dummy)
        {
                return lower_bound(data.begin(), data.end(), dummy, [](const Pair *a, const Pair *b) {
            return a->key < b->key;
        });
    }

(typename je tam preto, lebo typ Pair závisí na template parametroch. Viac tu, proste to ber tak že to typename tam musí byť :-D )

Alebo jednoduchšie riešenie je zistiť typ pomocou decltype a pomocou typedef deklarovať nový typ:

typedef decltype(data.begin()) typ_iteratora;
Akceptované řešení
+20 Zkušeností
+2,50 Kč
Řešení problému
Nahoru Odpovědět
30.3.2018 20:34
'long long long' is too long for GCC
Avatar
Martin Dráb
Tvůrce
Avatar
Odpovídá na Petr Čech
Martin Dráb:30.3.2018 20:56

Jestli dobře vidím, tak atribut data, ze kterého přes auto bereš iterátory, má pro funkce begin a end definovány návratové typy

std::vector<Pair *>::iterator
std::vector<Pair *>::const_iterator

Viz třeba dokumentace k metodě begin (mrkni třeba na ten příklad).
http://www.cplusplus.com/…ector/begin/

Máš pravdu, že pokud se třeba ve Visual Studiu podíváš na ty typy, je to šílenost, ale dokumentace existuje a je dobrá. Nemá smysl kvůli tomu na ten jazyk nadávat. Prostě u něj potřebuješ trochu více znalostí než u jiných.

Samozřejmě, kouzla s decltype budou lepší.

Nahoru Odpovědět
30.3.2018 20:56
2 + 2 = 5 for extremely large values of 2
Avatar
Petr Čech
Tvůrce
Avatar
Odpovídá na Martin Dráb
Petr Čech:30.3.2018 22:52

C'm on, teď jsem si z errorů kompilátoru vytáhl nějaký typ, co se mu nepodařilo převést. Má 1365 znaků. To je přeci naprosto absurdní a programátor by se v takovém bordelu neměl hrabat jen proto, že se někdo neobtěžoval implementovat skutečnou generiku ... nebo rozumnou deklaraci typů obecně :D
1365 znaků má ten typ, ne ta chyba.

Editováno 30.3.2018 22:53
Nahoru Odpovědět
30.3.2018 22:52
the cake is a lie
Avatar
Martin Dráb
Tvůrce
Avatar
Odpovídá na Petr Čech
Martin Dráb:30.3.2018 23:37

programátor by se v takovém bordelu neměl hrabat jen proto, že se někdo neobtěžoval implementovat skutečnou generiku ... nebo rozumnou deklaraci typů obecně

Ta generika je implementována jinak než v ostatních jazycích. Jelikož se řeší čistě za překladu (v zásadě to jsou taková o hodně lepší preprocesorová makra), dovoluje dělat některé vylomeniny (například můžeš na generickém typu volat libovolné metody a překladač jejich existenci začne řešit až v případě, že deklaruješ instanci dané generiky... což mi v některých jazycích dost chybí, šetří to čas a řádky kódu, nesvazuje tě tolik dědičnost/poly­morfismus).

Překladač ti do chybové hlášky píše název typu, jak si jej on vytvořil a odekoroval. Zrovna tvůj případ je, jestli jsem jej dobře pochopil, využití knihovní funkce, takže tam typ krásně najdeš v dokumentaci (možná bys i nějaký rozumný našel, pokud byses podíval na definici té funkce v příslušném hlavičkovém souboru... bohužel třeba MSVS ty typy u našeptávače překládá dost "do mrtě", takže jsou jejich názvy dlouhé a ne úplně přehledné (protože se prostě jde přes pojmenované typy, co to dá).

Proč jsi nepoužil ten const iterator? U STL kontejnerů je právě konvence, že iterátory se jmenují std::kontejner<ty­py>::(const_)i­terator. S C++11 navíc přibylo řešení případu procházení celého kontejneru bez použití iterátoru

for (auto & prvek : kontejner) { . . . }

kde prvek bude typu odpovídajícímu referenci na postupně všechny prvky toho kontejneru (to referentítko je tam možná zbytečné). Takže obdoba podobně vypadajícíh cyklů v jiných jazycích.

Jinak nějakých 1365 znaků není nic extra :-). Před lety byla soutěž o vygenerování nejdelší chybové hlášky v C++ a to byly gigabajty, ne-li jejich desítky :-).

Nahoru Odpovědět
30.3.2018 23:37
2 + 2 = 5 for extremely large values of 2
Avatar
Petr Čech
Tvůrce
Avatar
Odpovídá na Martin Dráb
Petr Čech:30.3.2018 23:48

Const iterátor jsem nakonec použil a jsem s tím kódem teď spokojen, jen mě štve, že se k tomu nemůžu dobrat z těch chybových hlášek. Já jsem si dokumentaci pročítal, říká, že vrací

iterator begin() noexcept;
const_iterator begin() const noexcept;

Ale nějak se nezmiňuje o tom, že iterator je subclass od vector a mě to nenapadlo.

Jinak nějakých 1365 znaků není nic extra :-). Před lety byla soutěž o vygenerování nejdelší chybové hlášky v C++ a to byly gigabajty, ne-li jejich desítky :-).

Můj point přesně - žádný jiný jazyk (který znám :D) ti něco takového nevyhodí a člověk z toho může dokonce většinou poznat, co je vlastně špatně místo těch hor z větší části bordelu, co vyhodí c++ kompilátory.

Nahoru Odpovědět
30.3.2018 23:48
the cake is a lie
Děláme co je v našich silách, aby byly zdejší diskuze co nejkvalitnější. Proto do nich také mohou přispívat pouze registrovaní členové. Pro zapojení do diskuze se přihlas. Pokud ještě nemáš účet, zaregistruj se, je to zdarma.

Zobrazeno 6 zpráv z 6.