abclinuxu.cz AbcLinuxu.cz itbiz.cz ITBiz.cz HDmag.cz HDmag.cz abcprace.cz AbcPráce.cz
Inzerujte na AbcPráce.cz od 950 Kč
Rozšířené hledání
×
    dnes 04:55 | Zajímavý software

    Microsoft zveřejnil na GitHubu zdrojové kódy MS-DOSu 4.0 pod licencí MIT. Ve stejném repozitáři se nacházejí i před lety zveřejněné zdrojové k kódy MS-DOSu 1.25 a 2.0.

    Ladislav Hagara | Komentářů: 0
    včera 17:33 | Nová verze

    Canonical vydal (email, blog, YouTube) Ubuntu 24.04 LTS Noble Numbat. Přehled novinek v poznámkách k vydání a také příspěvcích na blogu: novinky v desktopu a novinky v bezpečnosti. Vydány byly také oficiální deriváty Edubuntu, Kubuntu, Lubuntu, Ubuntu Budgie, Ubuntu Cinnamon, Ubuntu Kylin, Ubuntu MATE, Ubuntu Studio, Ubuntu Unity a Xubuntu. Jedná se o 10. LTS verzi.

    Ladislav Hagara | Komentářů: 7
    včera 14:22 | Komunita

    Na YouTube je k dispozici videozáznam z včerejšího Czech Open Source Policy Forum 2024.

    Ladislav Hagara | Komentářů: 1
    včera 13:22 | Nová verze

    Fossil (Wikipedie) byl vydán ve verzi 2.24. Jedná se o distribuovaný systém správy verzí propojený se správou chyb, wiki stránek a blogů s integrovaným webovým rozhraním. Vše běží z jednoho jediného spustitelného souboru a uloženo je v SQLite databázi.

    Ladislav Hagara | Komentářů: 0
    včera 12:44 | Nová verze

    Byla vydána nová stabilní verze 6.7 webového prohlížeče Vivaldi (Wikipedie). Postavena je na Chromiu 124. Přehled novinek i s náhledy v příspěvku na blogu. Vypíchnout lze Spořič paměti (Memory Saver) automaticky hibernující karty, které nebyly nějakou dobu používány nebo vylepšené Odběry (Feed Reader).

    Ladislav Hagara | Komentářů: 0
    včera 04:55 | Nová verze

    OpenJS Foundation, oficiální projekt konsorcia Linux Foundation, oznámila vydání verze 22 otevřeného multiplatformního prostředí pro vývoj a běh síťových aplikací napsaných v JavaScriptu Node.js (Wikipedie). V říjnu se verze 22 stane novou aktivní LTS verzí. Podpora je plánována do dubna 2027.

    Ladislav Hagara | Komentářů: 0
    včera 04:22 | Nová verze

    Byla vydána verze 8.2 open source virtualizační platformy Proxmox VE (Proxmox Virtual Environment, Wikipedie) založené na Debianu. Přehled novinek v poznámkách k vydání a v informačním videu. Zdůrazněn je průvodce migrací hostů z VMware ESXi do Proxmoxu.

    Ladislav Hagara | Komentářů: 0
    včera 04:11 | Nová verze

    R (Wikipedie), programovací jazyk a prostředí určené pro statistickou analýzu dat a jejich grafické zobrazení, bylo vydáno ve verzi 4.4.0. Její kódové jméno je Puppy Cup.

    Ladislav Hagara | Komentářů: 0
    24.4. 22:44 | IT novinky

    IBM kupuje společnost HashiCorp (Terraform, Packer, Vault, Boundary, Consul, Nomad, Waypoint, Vagrant, …) za 6,4 miliardy dolarů, tj. 35 dolarů za akcii.

    Ladislav Hagara | Komentářů: 12
    24.4. 15:55 | Nová verze

    Byl vydán TrueNAS SCALE 24.04 “Dragonfish”. Přehled novinek této open source storage platformy postavené na Debianu v poznámkách k vydání.

    Ladislav Hagara | Komentářů: 0
    KDE Plasma 6
     (73%)
     (9%)
     (2%)
     (16%)
    Celkem 769 hlasů
     Komentářů: 4, poslední 6.4. 15:51
    Rozcestník

    Dotaz: C++ Template a návratový typ

    13.7.2018 21:16 Pavel
    C++ Template a návratový typ
    Přečteno: 2345×
    Zdravím, mám né zrovna šikovně navrženou část aplikace v C++ a pokouším se to zjednodušit - nejspíš pomocí templatů, které jsem ale už dost zapomněl, takže bych tady chtěl poprosit o radu...

    Mam data dost ošlivě uložené ve třídě ze které je získávám jako pole pomocí metod readXY podle datových typů. Původně byly 2, teď už jich je hromada:
    
    Class Data
    {
    public:
    ...
    std::vector<u8> readU8(Info i);
    std::vector<float> readFloat(Info i);
    std::vector<std::vector<float>> readFloatVector(Info i);
    ...
    }
    Ve třídě Info je hromada informací podle kterých ty data získávám + jejich datový typ uložený jako enum class
    
    enum class DatovyTyp : u8 {U8,Float,FloatVector,...}
    class Info
    {
    public:
    ...
    std::string jmeno;
    DatovyTyp typ;
    ...
    }
    
    Celé použití je dost nešikovné, protože když chci získat všechny data a pak je zase dál použít, musím mít IF pro každý datový typ: (navazující metody už jsou teplate nebo přetížené, takže umí pracovat se všemi datovými typy, které potřebuju)
    
    Data d(...);
    for(...)
    {
      Info i(...);
      if(i.typ == DatovyTyp::Float)
      {
        std::vector<float> tmp = d.readFloat(i);
        nějakáPřetíženáFunkceNeboTemplate(tmp,...);
      }
      else if(i.typ == VariableType::U8)
      {
        nějakáPřetíženáFunkceNeboTemplate(d.readU8(i),...);
      }
    }
    
    Použití template ve smyslu:
    
    template <typename T>
        T read(Info i)
    {
    ...
    
    mě sice sjednotí všechny readXY do jedné šablony, ale pořád budu muset mít IF pro každý datový typ
    
    if(i.typ == DatovyTyp::Float)
    {
      std::vector<float> tmp = d.read<float>(i);
      nějakáPřetíženáFunkceNeboTemplate(tmp,...);
    }
    else if(i.typ == VariableType::U8)
    {
      nějakáPřetíženáFunkceNeboTemplate(d.read<u8>(i),...);
    }
    
    Chtěl bych idálně mít nějaký kouzelný template, který vrací datový typ podle toho enum class DatovyTyp - což pokud vím nejde.

    Takže se ptám, jestli existuje nějaká možnost jak uložit informaci o datovém typu tak, abych to potom mohl použít k určení návratového datového typu v template? Zatím jsem nic nenašel a co se pamatuju, tak tohle template neumožňují - existuje nějaká možnost jak to obejít?

    Nebo jak to celé upravit nějak jinak, abych se vyhnul IF pro každý datový typ?

    Díky.

    Odpovědi

    13.7.2018 23:30 MadCatX
    Rozbalit Rozbalit vše Re: C++ Template a návratový typ
    Jestli to chápu správně, potřebuješ se rozhodnout za běhu, jaká data chceš z té třídy Data získat. To se čistě templaty vyřešit nedá, protože templaty v C++ se řeší pouze při překladu. Nějaké runtimové logice s větvením se tedy nevyhneš. Dá se to ale částečně zjednodušit tím, že logiku, která za běhu zjistí požadovaný datový typ a podle toho zavolá příslušnou obsluhu přesuneš do jedné flexibilní funkce. Nějaký nástin, jak na to můžeš najít třeba tady: https://pastebin.com/XUvcSJUr. Vtip je v tom, že to, co se předává dispatcheru jako templatový parameter P lze naimplemetovat libovolně, zatímco dispatcher bude vždy jen jeden.

    Dalo by se to samozřejmě rozšířit i pro případy, že by měl dispatcher něco vracet apod. ale princip by byl stejný...
    13.7.2018 23:46 MadCatX
    Rozbalit Rozbalit vše Re: C++ Template a návratový typ
    Šikovnější verze, která se neomezuje jen na funkci read():

    https://pastebin.com/5GuZk4m5
    16.7.2018 10:32 Pavel
    Rozbalit Rozbalit vše Re: C++ Template a návratový typ
    Díky moc, něco takového jsem hledal... jen jsem doufal v trochu jednodušší použití. Určitě to v nějaké podobě použiju, ale má to bejt zároveň rozhraní knihovny kterou budou používat i lidi pro který je šablona sprostý slovo - takže moc nepředpokládám, že by si někdo implementoval P.

    Po delší době jsem zjistil, kolik jsem toho a zapomněl a jak moc mi ujíždí vlak... každopádně ještě jednou díky.

    16.7.2018 11:59 MadCatX
    Rozbalit Rozbalit vše Re: C++ Template a návratový typ
    P, která s budou používat nejčastěji můžeš implementovat ty jako autor rozhraní s tím, že coder monkey prostě zavolá nějaký wrapper okolo dispatcheru a nebude řešit, co se vevnitř děje. std::variant v kódu není nejspíš proto, že je to věcička až z C++17 a starší překladače to nezbaští.
    16.7.2018 13:19 Pavel
    Rozbalit Rozbalit vše Re: C++ Template a návratový typ
    Ano - přesně tak jsem to myslel - že udělám dvě nejčastější použití a celé to zabalím...

    "std::variant v kódu není nejspíš proto, že je to věcička až z C++17 a starší překladače to nezbaští" ->

    Teď nevím co tím je myšleno... původně se ve třídě Data používal boost::any, který je v boost od 2007 (boost 1.34) stejně jako boost::variant. Spíš jsem se divil, že byl použit any místo variant, který by byl asi vhodnější (má daný výčet povolených typů, do any můžu uložit cokoliv) - ale zas takový rozdíl v nich nevidím. Stejně použití variant / any ať už boost nebo std v tomhle případě nic neřeší - stejně budu znát datový typ, který z toho chci vytáhnout, až za běhu - je jedno, jestli použiju vlastní template nebo std::get<float>(variant) ... jestli mi teda zase něco neuniklo ;-)
    14.7.2018 10:18 Sten
    Rozbalit Rozbalit vše Re: C++ Template a návratový typ
    Jestli to chápu dobře, tak chcete něco jako std::variant? Tam se to řeší přes visitor patern.
    14.7.2018 11:44 MadCatX
    Rozbalit Rozbalit vše Re: C++ Template a návratový typ
    To jsem si původně myslel taky ale z dotazu není jasné, zda obsahuje třída Data data vždy jen jednoho typu nebo zda je možné zavolat d.readFloat() a d.readU8() na jedné instanci té třídy. To by se variantem myslím řešit nedalo. Aspoň trochu flexibilní logika, jak řešit ten druhý případ by mohla vypadat třeba takto:
    #include <iostream>
    #include <vector>
    
    enum class TypeID {
    	String,
    	Float,
    	Integer
    };
    
    template <TypeID>
    struct TypeIdentifier {
    };
    
    template <>
    struct TypeIdentifier<TypeID::String> {
    	typedef std::string type;
    };
    
    template <>
    struct TypeIdentifier<TypeID::Float> {
    	typedef float type;
    };
    
    template <>
    struct TypeIdentifier<TypeID::Integer> {
    	typedef int32_t type;
    };
    
    struct Data {
    	template <typename T>
    	std::vector<T> read();
    };
    
    
    template <>
    std::vector<std::string> Data::read()
    {
    	return std::vector<std::string>{ "Zero", "One", "Two" };
    }
    
    template <>
    std::vector<float> Data::read()
    {
    	return std::vector<float>{ 0.1, 0.2, 0.3 };
    }
    
    template <>
    std::vector<int32_t> Data::read()
    {
    	return std::vector<int32_t>{ 10, 20, 30 };
    }
    
    template <typename T>
    void print(const T &t)
    {
    	for (auto && i : t)
    		std::cout << i << " ";
    	std::cout << "\n";
    }
    
    template <typename T>
    void printReverse(const T &t)
    {
    	for (auto it = t.rbegin(); it != t.rend(); it++)
    		std::cout << *it << " ";
    	std::cout << "\n";
    }
    
    template <template <typename> class P, typename S, typename... Args>
    void dispatcher(const TypeID id, S &s, Args... args)
    {
    	switch (id) {
    	case TypeID::String:
    		P<TypeIdentifier<TypeID::String>::type>::call(s, std::forward<Args>(args)...); break;
    	case TypeID::Float:
    		P<TypeIdentifier<TypeID::Float>::type>::call(s, std::forward<Args>(args)...); break;
    	case TypeID::Integer:
    		P<TypeIdentifier<TypeID::Integer>::type>::call(s, std::forward<Args>(args)...); break;
    	}
    }
    
    template <typename T>
    struct Proc {
    	static void call(Data &d)
    	{
    		auto v = d.read<T>();
    		print(v);
    	}
    };
    
    template <>
    struct Proc<int32_t> {
    	static void call(Data &d)
    	{
    		std::cout << "Specialization for int32_t\n";
    
    		auto v = d.read<int32_t>();
    		print(v);
    	}
    };
    
    template <typename T>
    struct ProcTwo {
    	template <typename... Args>
    	static void call(Data &d, Args ...)
    	{
    		auto v = d.read<T>();
    		printReverse(v);
    	}
    };
    
    template <>
    struct ProcTwo<float> {
    	static void call(Data &d, int i)
    	{
    		std::cout << "Specialization for float: " << i << "\n";
    
    		auto v = d.read<float>();
    		printReverse(v);
    	}
    
    	template <typename... Args>
    	static void call(Data &, Args...)
    	{
    		throw std::runtime_error("Function called with invalid parameters");
    	}
    };
    
    int main()
    {
    	Data d;
    
    	dispatcher<Proc>(TypeID::String, d);
    	dispatcher<Proc>(TypeID::Float, d);
    	dispatcher<Proc>(TypeID::Integer, d);
    
    	dispatcher<ProcTwo>(TypeID::String, d);
    	dispatcher<ProcTwo>(TypeID::Float, d, 66);
    	//dispatcher<ProcTwo>(TypeID::Float, d);    /* Throws at runtime */
    	dispatcher<ProcTwo>(TypeID::Integer, d);
    
    	return 0;
    }
    
    16.7.2018 10:39 Pavel
    Rozbalit Rozbalit vše Re: C++ Template a návratový typ
    Třída Data právě obsahuje vždy data víc typů... původně byly interně uloženy jako boost::any (už se nepamatuju proč se nepoužil variant), ale kvůli rychlosti a velikosti se to změnilo na dost ošlivej bastl. I kdyby se použil std::variant, tak by to zrovna v tomhle ničemu nepomohlo (jinde jo, takže se o tom čas od času uvažuje)...
    14.7.2018 12:29 Kit | skóre: 45 | Brno
    Rozbalit Rozbalit vše Re: C++ Template a návratový typ
    Co znamená "získat data ze třídy"? Co takhle raději místo toho "zpracovat data v objektu"? Tím se hromada zmíněných problémů vyřeší, protože ify nebudou potřebné.
    Komentáře označují místa, kde programátor udělal chybu nebo něco nedodělal.
    14.7.2018 22:02 zvol
    Rozbalit Rozbalit vše Re: C++ Template a návratový typ
    Můžete tím enumem "indexovat" variadický template.

    ideone.com/w1CLnF

    Ukázka:
    template<int N, class Head, class... Tail>
    struct Dispatch {
      static void dispatch(const Info& i, const Data& d) {
        if (i.typ == N)
          perform<Head>(i, d);
        else
          Dispatch<N+1, Tail...>::dispatch(i, d);
      }
    };
    

    Založit nové vláknoNahoru

    Tiskni Sdílej: Linkuj Jaggni to Vybrali.sme.sk Google Del.icio.us Facebook

    ISSN 1214-1267   www.czech-server.cz
    © 1999-2015 Nitemedia s. r. o. Všechna práva vyhrazena.