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

Nová čísla časopisů od nakladatelství Raspberry Pi: MagPi 81 (pdf), HackSpace 18 (pdf), Hello World 8 (pdf) a Wireframe 11 (pdf) a 12 (pdf).

Ladislav Hagara | Komentářů: 0
dnes 01:22 | Nová verze

Po více než 4 měsících vývoje od vydání verze 15 byla vydána nová stabilní verze 16 open source systému Nextcloud (Wikipedie), forku ownCloudu, umožňujícího provoz vlastního cloudového úložiště. Přehled novinek i s náhledy v příspěvku na blogu. Pro vyzkoušení Nextcloudu je k dispozici demo (aktuálně verze 15).

Ladislav Hagara | Komentářů: 0
dnes 01:00 | Nová verze

Node.js Foundation, oficiální projekt konsorcia Linux Foundation, oznámila vydání verze 12.0.0 (Current) otevřeného multiplatformního prostředí pro vývoj a běh síťových aplikací napsaných v JavaScriptu Node.js (Wikipedie). Přehled novinek v článku na Medium. Verze 12 se v říjnu stane novou aktivní LTS verzí. Podpora je plánována do dubna 2022.

Ladislav Hagara | Komentářů: 1
dnes 00:44 | Nová verze

Byla vydána verze 11.10 open source alternativy GitHubu, tj. softwarového nástroje s webovým rozhraním umožňujícího spolupráci na zdrojových kódech, GitLab (Wikipedie). Představení nových vlastností i s náhledy v příspěvku na blogu.

Ladislav Hagara | Komentářů: 0
dnes 00:11 | IT novinky

OpenAI, nezisková organizace pro výzkum umělé inteligence (AI), představila projekt MuseNet. Jedná se o hlubokou neuronovou síť, která dokáže generovat čtyřminutové hudební skladby s 10 různými nástroji a kombinovat styly od country přes Mozarta až po Beatles.

Ladislav Hagara | Komentářů: 5
včera 16:00 | Pozvánky

Spolek OpenAlt zve příznivce otevřených řešení a přístupu na 163. brněnský sraz, který proběhne v pátek 26. dubna od 18:00 v indické restauraci Everest na adrese Veveří 61.

Ladislav Hagara | Komentářů: 5
včera 15:33 | IT novinky

Všem dívkám v ICT vše nejlepší k dnešnímu Mezinárodnímu dni dívek v ICT (Wikipedie, Girls in ICT Day, YouTube).

Ladislav Hagara | Komentářů: 8
včera 12:22 | Nová verze

Byla vydána verze 1.12 systému pro správu a verzování zdrojových kódů Apache Subversion (Wikipedie). Přehled novinek v poznámkách k vydání.

Ladislav Hagara | Komentářů: 11
včera 12:11 | Zajímavý článek

Mozilla zveřejnila každoroční Internet Health Report, který popisuje aktuální společenská témata související s využíváním Internetu. Tentokrát se dotýkají mj. etiky algoritmů strojového učení, cílené reklamy a „chytrých měst“.

Fluttershy, yay! | Komentářů: 2
včera 08:44 | Nová verze

Webová aplikace pro správu repozitářů v gitu Gitea vyšla v nové verzi 1.8.0. Nově poskytuje OAuth 2.0, umožňuje archivaci repozitářů, skrývání organizací jako interních či soukromých, zamykání konverzací a mnoho dílčích změn.

Fluttershy, yay! | Komentářů: 6
Používáte headset pro virtuální realitu?
 (1%)
 (3%)
 (2%)
 (18%)
 (1%)
 (75%)
Celkem 241 hlasů
 Komentářů: 12, poslední 18.4. 01:19
Rozcestník

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

13.7.2018 21:16 Pavel
C++ Template a návratový typ
Přečteno: 2259×
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: 43 | 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.