Programim dhe zhvillim, javascript, python, php, html

Si të specializohet pjesërisht një shabllon strukturor për treguesin e funksionit jo-anëtar dhe anëtar

Unë jam duke bërë disa metaprogramime shabllone që përfshijnë tregues funksionesh. Për shkak se llojet e funksioneve për treguesit e funksionit jo-anëtar dhe anëtarë janë të ndryshëm, unë po përpiqem të specializohem midis të dyjave. Për më tepër, unë dua që treguesi i funksionit të jepet si një argument shabllon jo-tip në vend të një parametër të një funksioni në strukturë. Deri tani ja çfarë kam tentuar:

template <typename T, T>
struct register_method;

template <typename R, typename... Args>
struct register_method<R(Args...), R (*method)(Args...)>
{
    static R invoke(Args&&... params)
    {
        return (*method)(std::forward<Args>(params)...);
    }
};

template <typename T, typename R, typename... Args>
struct register_method<R(Args...), R (T::*method)(Args...)>
{
    static R invoke(T* instance, Args&&... params)
    {
        return (instance->*method)(std::forward<Args>(params)...);
    }
};

Megjithatë kjo nuk arrin të përpilohet (këtu është vetëm gabimi i parë):

prog.cc:14:48: error: 'Args' does not refer to a value
struct register_method<R(Args...), R (*method)(Args...)>
                                               ^
prog.cc:13:35: note: declared here
template <typename R, typename... Args>
                                  ^

Nuk jam vërtet i sigurt se çfarë po përpiqet të më thotë. Qëllimi im është të përdor këto objekte si kjo:

void the_func(float val)
{
    std::cout << "the_func called: " << val << "\n";
}

int main()
{
    register_method<decltype(&the_func), &the_func>::invoke(50.f);
}

Si mund ta bëj këtë të funksionojë? Nëse ka një mundësi për të thjeshtuar, kjo do të ishte gjithashtu e mrekullueshme (për shembull, nëse mund të shpëtoj duke kaluar vetëm treguesin e funksionit tek shablloni në vend që të bëj gjithashtu një decltype, i cili duhet të zvogëlojë pllakën e bojlerit.

EDIT: Gjithashtu dua të shtoj se arsyeja që unë kam nevojë për specializime të veçanta për funksionet jo-anëtare dhe ato anëtare shtrihet përtej vetëm llojeve të funksioneve që janë të ndryshme. Ekziston një gjendje statike midis të dyve që është e ndryshme, për shkak të rregullave të biznesit që unë i bashkangjit llojeve të ndryshme të funksioneve. I kam lënë jashtë këto detaje këtu për ta mbajtur pyetjen të thjeshtë.

c++
24.10.2019

  • Nuk jam i sigurt se cili është rasti juaj i përdorimit, por duket sikur po përpiqeni të krijoni std::invoke. Cilin version të C++ po përdorni? 24.10.2019
  • @NathanOliver Unë jam duke përdorur C++17 me Clang. Ndërsa qëllimi im është i ndryshëm, ndërfaqja ime me siguri do të ngjajë me atë të std::invoke. Megjithatë, e ndryshova pyetjen time me mohimin se ka më shumë logjikë biznesi të bashkangjitur me çdo specializim që nuk tregohet këtu, kështu që nuk po krijoj vetëm një mbështjellës të thjeshtë thirrjesh, megjithëse ky është qëllimi përfundimtar. 24.10.2019
  • Nëse përdorni C++17, mund të përdorni template <auto method> struct register_method. 24.10.2019
  • @HolyBlackCat A mund të jepni një shembull më të plotë në formën e një përgjigjeje? Kam harruar plotësisht për auto në shabllone, kjo mund të jetë ajo që më nevojitet, megjithëse jam ende i shqetësuar për kërkesën tjetër: Të jesh në gjendje të ndajë llojin e kthimit dhe argumentet. Nuk jam i sigurt se si e arrini këtë në rastin auto. 24.10.2019
  • Nuk ka lidhje me gabimin që kërkon pyetja juaj, por përcjellja juaj e përsosur nuk funksionon. Args në nënshkrimin e anëtarëve tuaj invoke nuk po përdoret në një kontekst të deduktuar. 24.10.2019

Përgjigjet:


1

Ja se si mund ta rregulloni kodin:

template <typename T, T>
struct register_method;

template <typename R, typename... Args, R (*method)(Args...)>
struct register_method<R (*)(Args...), method>
{
    template <typename ...P>
    static R invoke(P &&... params)
    {
        return (*method)(std::forward<P>(params)...);
    }
};

template <typename T, typename R, typename... Args, R (T::*method)(Args...)>
struct register_method<R (T::*)(Args...), method>
{
    template <typename ...P>
    static R invoke(T *instance, P &&... params)
    {
        return (instance->*method)(std::forward<P>(params)...);
    }
};

Vini re se duhet të prezantoni një paketë të veçantë parametrash që referencat e përcjelljes të funksionojnë, pasi ato funksionojnë vetëm nëse përcaktohet parametri i shabllonit.


Dhe këtu është një zgjidhje alternative duke përdorur parametrat e shabllonit C++17 auto:

template <auto method>
struct register_method;

template <typename R, typename... Args, R (*method)(Args...)>
struct register_method<method>
{
    template <typename ...P>
    static R invoke(P &&... params)
    {
        return (*method)(std::forward<P>(params)...);
    }
};

template <typename T, typename R, typename... Args, R (T::*method)(Args...)>
struct register_method<method>
{
    template <typename ...P>
    static R invoke(T *instance, P &&... params)
    {
        return (instance->*method)(std::forward<P>(params)...);
    }
};
24.10.2019
  • Versioni i zgjidhjes C++17 që kishit fshirë më parë ishte më i mirë se ky. Në vend që të deklaroj P përsëri për invoke(), unë thjesht përdor Args&&... params dhe funksionon pa deklaruar argumente shabllone për funksionin statik 24.10.2019
  • @void.pointer Nuk funksionon vërtet. Le të themi se keni void foo(int). Atëherë Args është int, dhe Args&&... params është int &&params. Pra, kalimi i një lvlere, p.sh. int x = 1; ...::invoke(x); nuk do të funksionojë. 24.10.2019
  • Unë besoj se Args&&... përfaqëson një referencë universale, kështu që me të vërtetë do të hynte si int& params, mendoj. 25.10.2019
  • @void.pointer Jo, nuk funksionon. Do të bëhet int &params, nëse Args disi ishte int &. Por Args është tashmë int. Që një referencë të jetë përcjellëse (aka universale), duhet të lini përpiluesin të deduktojë llojin e parametrit. 25.10.2019
  • Keni të drejtë. Për shkak se shembulli im është pak mashtrues, mendova se ishte duke deduktuar Args përsëri, por nuk është, siç pohoni ju. Referencat e përcjelljes zbatohen vetëm për argumentet e modelit të funksionit. Faleminderit për zgjidhjen e orientuar në detaje. 25.10.2019

  • 2

    Specializimi duhet të duket si

    template <typename T, T>
    struct register_method;
    
    template <typename R, typename... Args, R (*method)(Args...)>
    struct register_method<R (*)(Args...), method>
    {
        static R invoke(Args... params)
        {
            return (*method)(std::forward<Args>(params)...);
        }
    };
    
    template <typename C, typename R, typename... Args, C (T::*method)(Args...)>
    struct register_method<R (C::*)(Args...), method>
    {
        static R invoke(T* instance, Args... params)
        {
            return (instance->*method)(std::forward<Args>(params)...);
        }
    };
    
    24.10.2019
  • Është një përdorim interesant i forward, më mori një sekondë për ta përpunuar. 24.10.2019
  • Meqenëse Args kalohet sipas vlerës, a nuk mund të përdorni vetëm move? 24.10.2019
  • @NathanOliver Jo domosdoshmërisht sipas vlerës, Args mund të përmbajë referenca. 24.10.2019
  • @HolyBlackCat Oh po. Faleminderit. 24.10.2019
  • Materiale të reja

    Masterclass Coroutines: Kapitulli-3: Anulimi i korutinave dhe trajtimi i përjashtimeve.
    Mirë se vini në udhëzuesin gjithëpërfshirës mbi Kotlin Coroutines! Në këtë seri artikujsh, unë do t'ju çoj në një udhëtim magjepsës, duke filluar nga bazat dhe gradualisht duke u thelluar në..

    Faketojeni derisa ta arrini me të dhënat false
    A e gjeni ndonjëherë veten duke ndërtuar një aplikacion të ri dhe keni nevojë për të dhëna testimi që duken dhe duken më realiste ose një grup i madh të dhënash për performancën e ngarkesës...

    Si të përdorni kërkesën API në Python
    Kërkesë API në GitHub për të marrë depot e përdoruesve duke përdorur Python. Në këtë artikull, unë shpjegoj procesin hap pas hapi për të trajtuar një kërkesë API për të marrë të dhëna nga..

    Një udhëzues hap pas hapi për të zotëruar React
    Në këtë artikull, do të mësoni se si të krijoni aplikacionin React, do të mësoni se si funksionon React dhe konceptet thelbësore që duhet të dini për të ndërtuar aplikacione React. Learning..

    AI dhe Psikologjia — Pjesa 2
    Në pjesën 2 të serisë sonë të AI dhe Psikologji ne diskutojmë se si makineritë mbledhin dhe përpunojnë të dhëna për të mësuar emocione dhe ndjenja të ndryshme në mendjen e njeriut, duke ndihmuar..

    Esencialet e punës ditore të kodit tim VS
    Shtesat e mia të preferuara - Git Graph 💹 Kjo shtesë është vërtet e mahnitshme, e përdor përpara se të filloj të punoj për të kontrolluar dy herë ndryshimet dhe degët më të fundit, mund të..

    Pse Python? Zbulimi i fuqisë së gjithanshme të një gjiganti programues
    Në peizazhin gjithnjë në zhvillim të gjuhëve të programimit, Python është shfaqur si një forcë dominuese. Rritja e tij meteorike nuk është rastësi. Joshja e Python qëndron në thjeshtësinë,..