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 21:33 | Nová verze

Byla vydána nová major verze 1.8.0 open source systému pro filtrování nevyžádané pošty Rspamd (GitHub, ChangeLog). Z novinek lze zmínit nový framework selectors, optimalizaci modulu ClickHouse nebo vylepšení webového rozhraní.

Ladislav Hagara | Komentářů: 0
dnes 18:44 | Bezpečnostní upozornění

Sabri Haddouche vytvořil stránku Browser Reaper, na které demonstruje zranitelnosti současných verzí webových prohlížečů Chrome, Safari i Firefox. Zveřejněné skripty dokážou zahltit nejen webové prohlížeče, ale v závislosti na nastavení, také celé operační systémy.

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

Byla vydána verze 11.3 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
22.9. 13:00 | Komunita

Do 30. října se lze přihlásit do dalšího kola programu Outreachy (Wikipedie), jehož cílem je přitáhnout do světa svobodného a otevřeného softwaru lidi ze skupin, jež jsou ve světě svobodného a otevřeného softwaru málo zastoupeny. Za 3 měsíce práce, od 4. prosince 2018 do 4. března 2019, v participujících organizacích lze vydělat 5 500 USD.

Ladislav Hagara | Komentářů: 96
21.9. 22:22 | Komunita

Společnost Purism představila kryptografický token Librem Key. Koupit jej lze za 59 dolarů. Token byl vyvinut ve spolupráci se společností Nitrokey a poskytuje jak OpenPGP čipovou kartu, tak zabezpečení bootování notebooků Librem a také dalších notebooků s open source firmwarem Heads.

Ladislav Hagara | Komentářů: 8
21.9. 20:33 | Nová verze

Společnost NVIDIA oficiálně vydala verzi 10.0 toolkitu CUDA (Wikipedie) umožňujícího vývoj aplikací běžících na jejich grafických kartách. Přehled novinek v poznámkách k vydání.

Ladislav Hagara | Komentářů: 0
21.9. 20:00 | Upozornění

Příspěvek Jak přežít plánovanou údržbu DNS na blogu zaměstnanců CZ.NIC upozorňuje na historicky poprvé podepsání DNS root zóny novým klíčem dne 11. října 2018 v 18:00. Software, který nebude po tomto okamžiku obsahovat nový DNSSEC root klíč, nebude schopen resolvovat žádná data. Druhým důležitým datem je 1. února 2019, kdy významní výrobci DNS softwaru, také historicky poprvé, přestanou podporovat servery, které porušují DNS standard

… více »
Ladislav Hagara | Komentářů: 11
21.9. 15:55 | Pozvánky

Spolek OpenAlt zve příznivce otevřených řešení a přístupu na 156. brněnský sraz, který proběhne v pátek 21. září od 18:00 v restauraci Na Purkyňce na adrese Purkyňova 80.

Ladislav Hagara | Komentářů: 0
21.9. 13:22 | Nová verze

Alan Griffiths z Canonicalu oznámil vydání verze 1.0.0 display serveru Mir (GitHub, Wikipedie). Mir byl představen v březnu 2013 jako náhrada X serveru a alternativa k Waylandu. Dnes Mir běží nad Waylandem a cílen je na internet věcí (IoT).

Ladislav Hagara | Komentářů: 0
20.9. 22:00 | Nasazení Linuxu
Stabilní aktualizace Chrome OS 69 (resp. Chromium OS), konkrétně 69.0.3497.95, přináší mj. podporu linuxových aplikací. Implementována je pomocí virtualizace, a proto je tato funkce také omezena na zařízení s dostatkem paměti a podporou hardwarové akcelerace, tudíž nejsou podporovány chromebooky s 32bitovými architekturami ARM, či Intel Bay Trail (tzn. bez Intel VT-x).
Fluttershy, yay! | Komentářů: 6
Na optické médium (CD, DVD, BD aj.) jsem naposledy vypaloval(a) data před méně než
 (13%)
 (14%)
 (21%)
 (23%)
 (25%)
 (4%)
 (0%)
Celkem 404 hlasů
 Komentářů: 34, poslední dnes 12:54
Rozcestník

C++ templaty, member function pointer

10.2.2017 16:32 | Přečteno: 699× | programovani | poslední úprava: 10.2.2017 16:31

Snazim se v jednom Qt projektu vylepsit system callbacku. Callback v sobe ma pointer na objekt, na kterym se ma provest a nazev funkce, ktera se ma spustit. Pouzivam QMetaObject::invokeMethod a tim padem je to zavisle na MOC a funkce musi byt bud slot nebo Q_INVOKABLE.

Dostal jsem napad, jak se toho zbavit.

Kod je zde

#include <typeinfo>
#include <typeindex>

class functor
{
public:
    template <typename A, typename... Ts> inline functor(A *o, void (A::*f)(Ts... args))
    {
        avec.insert(avec.end(), {typeid(Ts)...});

        obj = o;
        func = reinterpret_cast< void (functor::*)() >(f);
    }

    template <typename... Ts> inline void operator()(Ts... args)
    {
        std::vector<std::type_index> vec; // argumenty volani
        vec.insert(vec.end(), {typeid(Ts)...});

        if(avec == vec)
        {
            void (functor::*f)(Ts ...) = reinterpret_cast<void (functor::*)(Ts ...)>(func);
            (reinterpret_cast<functor*>(obj)->*f)(args ...);
        }
        else
            qDebug() << "functor invoked with bad arguments";
    }

private:
    void (functor::*func)();
    void *obj;

    std::vector<std::type_index> avec; // argumenty callbacku
};

Pouziti je jednoduchy, viz priklad. Vyhoda oproti jinym podobnym vecem je v tom, ze kontrola typu argumentu se deje v runtime a tim padem muzou mit vsechny callbacky jeden typ (i kdyz volaji funkce s ruznyma argumentama).

base *t = new base();
functor f(t, &base::torture); // vytvorim callback

f(); // zavolam ho

Rad bych od vas dostal nazor, jestli je to dobry napad, nebo neni, a proc (pripadne jestli nekde neumiraji kotatka kdyz delam reinterpret_cast).

       

Hodnocení: 100 %

        špatnédobré        

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

Komentáře

Vložit další komentář

10.2.2017 17:15 oryctolagus | skóre: 29 | blog: Untitled
Rozbalit Rozbalit vše Re: C++ templaty, member function pointer
Proč castuješ tu callback member funkci na member funkci toho funktoru? Pointer na member funkce jsou divný, můžou mít různý velikosti.

Stejnětak mi není jasný, proč castuješ A *o na *functor, možná to jen nechápu...
vlastikroot avatar 10.2.2017 18:26 vlastikroot | skóre: 24 | blog: vlastikovo | Milevsko
Rozbalit Rozbalit vše Re: C++ templaty, member function pointer
Ach tak, to vypada jako slusny zlo. Ten cast tam delam kvuli tomu, abych ochcal C++ a mohl ulozit pointer na jakoukoli class. Podle toho co jsi mi poslal by to mohl byt problem, jestli je kazdy pointer fyzicky jiny.
Sg1-game | We will destroys the Christian's legion ... and the cross, will be inverted | IP 80.188.182.6
10.2.2017 23:37 oryctolagus | skóre: 29 | blog: Untitled
Rozbalit Rozbalit vše Re: C++ templaty, member function pointer
Tak si tam dej nějakej datovej typ dostatečně velkej i na fakt obézní member pointery a do nej do kopíruj. Třeba struct { size_t a; size_t b; };

Nejspíš by se i našel způsob, jak během compile-time zjistit, jestli ten member func pointer není větší...
11.2.2017 00:31 Sten
Rozbalit Rozbalit vše Re: C++ templaty, member function pointer
To nebude fungovat v operator (), protože tam se to castuje na jiný typ, než který byl uložený, a každý může mít jinak velké member pointery.
11.2.2017 10:33 Jardík
Rozbalit Rozbalit vše Re: C++ templaty, member function pointer
Jestli kompiluje GCC na x86-64, tak všechny pointery na member fci jsou 16 bytů (8 bytů offset k this a 8 bytů buď adresa member fce, či index do vtable (Itanium C++ ABI). Na x86 je to stejné, akorát je to 4+4 bytů. Pokud by autorovi příspěvku nevadila další indirekce, mohl by urobit template member fci jako wrapper a pak by mu stačil jen obyč pointer na funkci. Protože narozdíl od obyč pointeru na funkci je pointer na member funkci compile-time konstanta a může být použit jako template argument. Úspora je však sporná - zase bude více kódu ve výsledné binárce pro wrapper funkci, ale když se bude opakovat stejný callback a nebudou všechny různé, úspora bude. A ten typeid check vyhoď z release buildu (#ifndef NDEBUG ... #endif)
vlastikroot avatar 11.2.2017 16:00 vlastikroot | skóre: 24 | blog: vlastikovo | Milevsko
Rozbalit Rozbalit vše Re: C++ templaty, member function pointer
Nevis jak je to na ARMu? Ten kod je cilenej na ARM.
Sg1-game | We will destroys the Christian's legion ... and the cross, will be inverted | IP 80.188.182.6
11.2.2017 16:30 Jardík
Rozbalit Rozbalit vše Re: C++ templaty, member function pointer
Můžeš zkusit web kompilátor tu, vpravo to ukazuje výsledný asm kód. Oba pointery na nevirtuální fce vypadají, že mají stejnou velikost (label .L5, u obou je "word" (asi velikost slova, kolik to je, nevím)). To implikuje i stejnou velikost pointeru na virtuální metodu (pointer na virtuální a nevirtuální metodu stejné signatury stejné třídy musí být kompatibilní).
11.2.2017 17:15 pc2005 | skóre: 36 | blog: GardenOfEdenConfiguration | liberec
Rozbalit Rozbalit vše Re: C++ templaty, member function pointer
16 bajtů složenýho ukazatele? To musí ten C++ kód neskutečně zpomalovat ne? (já jsem teda céčkař)
11.2.2017 17:37 Jardík
Rozbalit Rozbalit vše Re: C++ templaty, member function pointer
To je na member fcu, na statickou je to jen 8, jako v C. Pro každou member fcu je však možné vytvořit statickou wrapper fci, pomocí šablon.
Josef Kufner avatar 10.2.2017 17:31 Josef Kufner | skóre: 68
Rozbalit Rozbalit vše Re: C++ templaty, member function pointer
Nebylo by lepší hodit výjimku namísto ladicího výpisu?
Hello world ! Segmentation fault (core dumped)
vlastikroot avatar 10.2.2017 18:26 vlastikroot | skóre: 24 | blog: vlastikovo | Milevsko
Rozbalit Rozbalit vše Re: C++ templaty, member function pointer
Urcite, to neni hotovy kod, jen takovy napad.
Sg1-game | We will destroys the Christian's legion ... and the cross, will be inverted | IP 80.188.182.6
11.2.2017 10:36 Jardík
Rozbalit Rozbalit vše Re: C++ templaty, member function pointer
Používání výjimek na takovéto věci vidím jako zlo. Na programátorské chyby jsou asserty. Je ale smutné, že se místo nich ve standardní knihovně výjimky opravdu používají (třeba member fce at() různých kontejnerů).
11.2.2017 10:37 Jardík
Rozbalit Rozbalit vše Re: C++ templaty, member function pointer
Jinak důvodem je samozřejmě rychlost. Assert zpomalí či zabrání inlinování a optimalizací jen v debug buildu, kdeždo výjimka může mít negativní dopad na inlinování a jiné optimalizace v release buildu.
11.2.2017 14:42 Sten
Rozbalit Rozbalit vše Re: C++ templaty, member function pointer
Většina metod žádné výjimky nehází. at je hází úmyslně, neházející verze je operator [].

GCC má debug verzi STL, která asserty obsahuje.
11.2.2017 16:02 Jardík
Rozbalit Rozbalit vše Re: C++ templaty, member function pointer
Však nejsem blbej, já vím, že at() je hází úmyslně a taky vím, že operator[] ne. Ideální stav je, že je nehází ani at(), protože použití at() s neplatným indexem prostě považuji za programátorskou chybu a tedy by to mělo být ošetřeno assertem a né výjimkou. A operator[] by ten assert neměl obsahovat vůbec, aby nezdržoval debug build.
10.2.2017 22:19 kverulant
Rozbalit Rozbalit vše Re: C++ templaty, member function pointer
IMHO tam nebudou fungovat implicitni konverze.
11.2.2017 20:20 kverulant
Rozbalit Rozbalit vše Re: C++ templaty, member function pointer
A kdyz uz jsme u toho, tak to saskovani s vektorem je zbytecne. Typy argumentu jsou znamy v dobe prekladu, takze staci ulozit a porovnavat jen jeden slozeny typ, treba typeid(void(Ts...)) nebo neco podobneho.
10.2.2017 23:46 Sten
Rozbalit Rozbalit vše Re: C++ templaty, member function pointer
Ten reinterpret_cast nebude fungovat na virtuální metody.

Tohle se dělá tak, že při vytváření toho callbacku se uvnitř alokuje* šablonová implementace pro danou třídu mající virtuální metodu, kterou se to z operátoru () zavolá.

* S trochou čachrování (placement new) to většinou lze alokovat i v prostoru vyhrazeném na zásobníku a ušetřit dynamickou alokaci.
11.2.2017 00:06 Sten
Rozbalit Rozbalit vše Re: C++ templaty, member function pointer
Náčrt takového kódu (netestoval jsem, jestli funguje, ale pro ilustraci, jak by to mělo fungovat, snad stačí):

template <typename ReturnT, typename... ParamTs>
class Callback
{
protected:
    struct Iface
    {
        virtual ~Iface() {}
        virtual ReturnT operator ()(ParamTs... params) = 0;
    };

    template <typename Type>
    struct Impl
        : public Iface
    {
        using Func = ReturnT (Type::*)(ParamTs...);

        Impl(Type &obj, Func func)
            : obj(obj)
            , func(func)
        {}

        virtual ~Impl() {}

        virtual ReturnT operator ()(ParamTs... params)
        {
            return std::forward<ReturnT>(obj.*func(std::forward<ParamTs...>(params)));
        }

        Type &obj;
        Func func;
    };

    Iface& iface()
    {
        return *reinterpret_cast<Iface*>(buf);
    }

    size_t buf[4];

public:
    template <typename Type>
    Callback(Type &obj,
             typename Impl<Type>::Func func)
    {
        // Místo static_assert lze upravit, aby to použilo new
        static_assert(sizeof(Impl<Type>) <= sizeof(buf), "Buffer not large enough to capture callback");
        new (buf) Impl<Type>(obj, func);
    }

    ~Callback()
    {
        iface().~Iface();
    }

    ReturnT operator ()(ParamTs... params)
    {
        return std::forward<ReturnT>(iface()(std::forward<ParamTs...>(params)));
    }
};

Callback callback(t, &Type::getValueForInput);
int value = callback(input);
11.2.2017 00:14 Sten
Rozbalit Rozbalit vše Re: C++ templaty, member function pointer
Pár úprav:

std::forward na návratové hodnoty je zbytečný, navíc nebude fungovat s void.

virtual ReturnT operator ()(ParamTs... params) a virtual ~Impl()Impl by bylo lepší označit override.
11.2.2017 08:53 oryctolagus | skóre: 29 | blog: Untitled
Rozbalit Rozbalit vše Re: C++ templaty, member function pointer
Jestli může být Callback templatová třída, pak se rovnou může použít std::function, ne?
11.2.2017 10:42 Jardík
Rozbalit Rozbalit vše Re: C++ templaty, member function pointer
Autor píše, že chce, aby všechny functory měly stejný typ a nebyly šablony. Musí to tedy být wrapper na nějaký objekt s virtual fcemi pro volání, nebo použít ošklivý cast. Jinak reinterpret_cast nemění žádné hodnoty, takže fungovat by měl, pokud to zpět castne na stejně veliký typ.
11.2.2017 10:52 Jardík
Rozbalit Rozbalit vše Re: C++ templaty, member function pointer
Je to ale však prasárnička, o tom žádná. Ale nebude o nic větší, než moje prasárničky, kdy v pointeru vesele skladuju dalších 16 bitů nějakých hodnot, nebo používám double/NaN jako variant (hezky se tam vleze 47bit pointer, int, 47 bitů ze size_t, apod prasárničky, na dispatch tabulku máte celých 5 bitů).
11.2.2017 14:38 Sten
Rozbalit Rozbalit vše Re: C++ templaty, member function pointer
OK, zkusím vymyslet, jak tohle nějak rozumně zabalit. Tuhle implementaci (operator ()) by šlo zabalit přes reinterpret_cast, protože není polymorfní (takže je to jen pointer na funkci, kde první parametr je this), ale nebude to ověřovat typy parametrů.

Ten reinterpret_cast v původní implementaci nebude fungovat, pokud bude castovat z polymorfní třídy na nepolymorfní či obráceně, a nejspíš ani pokud bude mezi různými stromy polymorfních tříd, protože u virtuálních metod je to typicky implementováno jako index do vtable, nikoliv pointer.
11.2.2017 16:39 Jardík
Rozbalit Rozbalit vše Re: C++ templaty, member function pointer
Jak vypadá ukazatel na member funkci vím, psal jsem to někde výše. Na x86-64 je to 2x8 bytů, v jednom je offset pro this pointer (kvůli vícenásobné dědičnosti apod) a druhý je pointer na metodu, popř. offset do vtable (na rozlišení se používá přičtení jedničky, při volání se testuje a podle toho se pak provede buď jump na tu adresu, nebo se fetchne z vtable). Pointery na virtuální i nevirtuální metodu stejné třídy stejné signatury musí být "kompatibilní". ve smyslu stejná velikost a stejný formát, jinak by se pointer nedal předat někam, kde se neví, jak se má zavolat. Na x86-64 jsou takto kompatibilní i pointery na member funkce různých tříd, samozřejmě včetně vícenásobné i virtuální dědičnosti.
vlastikroot avatar 11.2.2017 15:53 vlastikroot | skóre: 24 | blog: vlastikovo | Milevsko
Rozbalit Rozbalit vše Re: C++ templaty, member function pointer
Jakto ze nebude fungovat? Muj kod virtualni metody pouziva, takze jsem je zkousel jako prvni. Chovalo se to tak jak bych ocekaval - kdyz vytvorim derived, pretypuju na base a udelam callback na base, volani spusti metodu v derived.
Sg1-game | We will destroys the Christian's legion ... and the cross, will be inverted | IP 80.188.182.6
11.2.2017 16:46 Jardík
Rozbalit Rozbalit vše Re: C++ templaty, member function pointer
Pokud použiješ reinterpret_cast na něco o stejné velikosti a pak na výsledek zase použiješ reinterpret_cast zpět na původní typ, tak to fungovat bude. Pouze se jinak interpretuje ta hodnota, ale nemění se. static_cast a dynamic_cast je na pointer na member funkci nepoužitelný, alespoň co já vím.
vlastikroot avatar 13.2.2017 23:54 vlastikroot | skóre: 24 | blog: vlastikovo | Milevsko
Rozbalit Rozbalit vše Re: C++ templaty, member function pointer
Tak jsem to predelal podle Stenovych pripominek, na test parametru se pouziva dynamic cast. Tohle se zda o dost cistsi nez ty reintepret casty a zvenku se to chova stejne jako puvodni kod.
class functor
{
protected:
    struct iface { virtual ~iface(){}; };
    template <typename... Ts> struct args : public iface
    {
        virtual void call(Ts...) = 0;
    };

    template <typename A, typename... Ts> struct impl : public args<Ts...>
    {
        A* obj;
        void (A::*func)(Ts...);

        impl(A* o, void (A::*f)(Ts...)) : obj(o), func(f) {}

        void call(Ts... args)
        {
            (obj->*func)(args...);
        }
    };

    size_t i[4];

public:
    template<typename A, typename... Ts> functor(A* o, void (A::*f)(Ts...))
    {
        static_assert(sizeof(impl<A, Ts...>) <= sizeof(i), "Buffer not large enough to capture callback");
        new (i) impl<A, Ts...>(o,f);
    }

    template<typename... Ts> void operator()(Ts... params)
    {
        args<Ts...> *a = dynamic_cast<args<Ts...>*>(reinterpret_cast<iface*>(i));

        if(a) a->call(params...);
        else qDebug() << "bad parameters";
    }
};
Sg1-game | We will destroys the Christian's legion ... and the cross, will be inverted | IP 80.188.182.6

Založit nové vláknoNahoru

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