C++ Academy · Oppitunti

Kutsuttavien olioiden valinta

Lambdat, bind vai osoittimet

Oppitunti 4/413 vaihetta

Kutsuttavien olioiden valinta on ilmainen C++ Academy-oppitunti CoddyKitissä. Tämä on oppitunti 4/4. Voit lukea tästä oppimispolusta kokonaan mitkä tahansa 3 oppituntia ilmaiseksi — sen jälkeen CoddyKit PRO avaa kaikki oppitunnit sekä käytännön harjoittelun sisäänrakennetulla koodieditorilla ja ympäri vuorokauden toimivalla tekoälytuutorilla. Oppitunti kuuluu C++ Academy-oppimispolkuun, ja edistymisesi synkronoituu verkon ja CoddyKit-sovelluksen välillä. C++ Academy-kurssilla on yhteensä 4 oppituntia.

Kutsuttavien työkalupakki

C++ tarjoaa useita tapoja välittää toiminnallisuutta: funktio-osoittimet, lambdat, funktorit, std::bind-kutsun ja std::function-tyypin. Kukin sopii erilaisiin tarpeisiin.

  • Yleinen kompromissi on nopeuden ja joustavuuden välillä.
  • Myös luettavuudella on merkitystä.
#include <iostream>

int twice(int x) { return x * 2; }

int main() {
    int (*fp)(int) = twice;
    auto lam = [](int x) { return x * 2; };
    std::cout << fp(5) << ' ' << lam(5) << '\n';
    return 0;
}

Milloin funktio-osoitinta kannattaa käyttää

Valitkaa funktio-osoitin, kun tarvitsette pienen, tilattoman takaisinkutsun ja haluatte C-yhteensopivuuden tai olemattomat lisäkustannukset.

#include <iostream>

void logMsg(const char* m) { std::cout << "LOG: " << m << '\n'; }

int main() {
    void (*handler)(const char*) = logMsg;
    handler("started");
    return 0;
}

Milloin lambdaa kannattaa käyttää

Lambda on moderni oletusvalinta: se on tiivis, voi kaapata tilaa, ja kääntäjä voi sijoittaa sen tehokkaasti suoraan koodiin malleissa ja algoritmeissa.

#include <iostream>
#include <vector>
#include <algorithm>

int main() {
    std::vector<int> v = {3, 1, 4, 1, 5};
    std::sort(v.begin(), v.end(), [](int a, int b) { return a > b; });
    for (int x : v) std::cout << x << ' ';
    std::cout << '\n';
    return 0;
}

Tilan kaappaaminen lambdassa

Lambda voi kaapata ympäröiviä muuttujia, toisin kuin funktio-osoitin, joten se sopii erinomaisesti kontekstia tarvitseviin takaisinkutsuihin.

#include <iostream>
#include <vector>
#include <algorithm>

int main() {
    int threshold = 3;
    std::vector<int> v = {1, 2, 3, 4, 5};
    int c = std::count_if(v.begin(), v.end(), [threshold](int x) { return x > threshold; });
    std::cout << c << '\n';
    return 0;
}

Milloin funktoria kannattaa käyttää

Funktori (operator()-operaattorilla varustettu struct) sopii uudelleenkäytettävään, nimettyyn operaatioon, joka voi sisältää asetuksia ja jota käytetään monissa paikoissa.

#include <iostream>
#include <vector>
#include <algorithm>

struct AboveThreshold {
    int limit;
    bool operator()(int x) const { return x > limit; }
};

int main() {
    std::vector<int> v = {1, 5, 2, 8};
    std::cout << std::count_if(v.begin(), v.end(), AboveThreshold{4}) << '\n';
    return 0;
}

Lambda vai bind

Molemmilla voi esitäyttää argumentteja. Lambda on yleensä selkeämpi ja helpompi optimoida kääntäjälle, joten suosikaa sitä std::bind-toiminnon sijaan.

#include <iostream>

int power(int base, int exp) {
    int r = 1;
    for (int i = 0; i < exp; ++i) r *= base;
    return r;
}

int main() {
    auto square = [](int x) { return power(x, 2); };
    std::cout << square(6) << '\n';
    return 0;
}

Milloin std::function-tyyppiä kannattaa käyttää

Käyttäkää std::function-tyyppiä, kun teidän on tallennettava kutsuttava olio, jonka konkreettista tyyppiä ei tunneta, esimerkiksi luokan jäsenenä tai säiliössä.

#include <iostream>
#include <functional>
#include <vector>

int main() {
    std::vector<std::function<int(int)>> pipeline;
    pipeline.push_back([](int x) { return x + 1; });
    pipeline.push_back([](int x) { return x * 3; });
    int v = 2;
    for (auto& f : pipeline) v = f(v);
    std::cout << v << '\n';
    return 0;
}

Mallit välttävät lisäkustannukset

Jos funktion tarvitsee vain vastaanottaa kutsuttava olio eikä tallentaa sitä, malliparametrin käyttö säilyttää täyden nopeuden välttämällä tyypin häivytystä.

#include <iostream>

template <typename F>
int applyTwice(int x, F f) { return f(f(x)); }

int main() {
    std::cout << applyTwice(3, [](int n) { return n + 10; }) << '\n';
    return 0;
}

Suorituskykyjärjestys

Karkeasti järjestys on seuraava: mallipohjainen kutsuttava olio tai tilaton lambda on nopein, funktio-osoitin on lähes yhtä nopea, ja std::function hitain epäsuoran kutsun ja mahdollisen muistivarauksen vuoksi.

#include <iostream>
#include <functional>

int main() {
    auto fast = [](int x) { return x + 1; };
    std::function<int(int)> flexible = fast;
    std::cout << fast(1) << ' ' << flexible(1) << '\n';
    return 0;
}

Valintaopas

Lyhyt opas:

  • Tarvitsetteko tallentaa minkä tahansa kutsuttavan olion? std::function.
  • Vastaanotatteko vain yhden kutsuttavan olion yleiskäyttöisessä funktiossa? Malliparametri.
  • Tarvitsetteko suoraan käyttöpaikassa määritettyä, tilaa sisältävää toiminnallisuutta? Lambda.
  • C-rajapinta tai tilaton toiminnallisuus? Funktio-osoitin.
#include <iostream>
#include <functional>

void runStored(const std::function<void()>& cb) { cb(); }

template <typename F>
void runGeneric(F f) { f(); }

int main() {
    runStored([] { std::cout << "stored\n"; });
    runGeneric([] { std::cout << "generic\n"; });
    return 0;
}

Kaiken yhdistäminen

Pieni tapahtumajärjestelmä voi vastaanottaa käsittelijöitä yleiskäyttöisesti mutta tallentaa ne std::function-muuttujaan, jotta ne voidaan kutsua myöhemmin.

#include <iostream>
#include <functional>
#include <vector>

struct Dispatcher {
    std::vector<std::function<void(int)>> handlers;
    template <typename F> void on(F f) { handlers.emplace_back(f); }
    void fire(int e) { for (auto& h : handlers) h(e); }
};

int main() {
    Dispatcher d;
    d.on([](int e) { std::cout << "got " << e << '\n'; });
    d.fire(7);
    return 0;
}

Pikatarkistus

Testatkaa, miten hyvin ymmärrätte kutsuttavien olioiden valintaa.

Kertaus

Opitte valitsemaan kutsuttavan olion:

  • funktio-osoitin tilattomille ja C-yhteensopiville takaisinkutsuille
  • lambda oletusvalintana suoraan määritettävälle, tilaa sisältävälle toiminnallisuudelle
  • funktori uudelleenkäytettäville nimetyille operaatioille
  • malliparametri, kun vain vastaanotatte kutsuttavan olion (nopein vaihtoehto)
  • std::function, kun teidän on tallennettava kutsuttava olio, jonka tyyppiä ei tunneta

Tämä päättää funktio-olioita ja std::bind-toimintoa käsittelevän kurssin.

Aloita maksutta

Opi C++ tekoälytuutorin avulla — ilmaiseksi

Kirjoita ja suorita oikeaa koodia selaimessa, saa välitöntä apua tekoälytuutorilta ympäri vuorokauden ja jatka siitä, mihin jäit, verkossa tai sovelluksessa.

Kurssit
51
Oppitunnit
203

Usein kysytyt kysymykset

Onko oppitunti ”Kutsuttavien olioiden valinta” ilmainen?

Kyllä — voit lukea täällä verkossa kokonaan ilmaiseksi mitkä tahansa C++ Academy-oppimispolun 3 oppituntia, myös oppitunnin “Kutsuttavien olioiden valinta”. Sen jälkeen CoddyKit PRO avaa kaikki oppitunnit sekä interaktiiviset harjoitukset sisäänrakennetulla koodieditorilla ja ympäri vuorokauden toimivalla tekoälytuutorilla. C++ Academy-kurssilla on yhteensä 4 oppituntia.

Mitä opin oppitunnilla ”Kutsuttavien olioiden valinta”?

Lambdat, bind vai osoittimet Harjoittelet C++ Academy-aihetta koodilla, jonka suoritat suoraan selaimessa. Ympäri vuorokauden käytettävissä oleva tekoälytuutori vastaa kysymyksiisi oppitunnin aikana.

Tarvitsenko kokemusta aloittaakseni C++ Academy-opiskelun?

Aiempi kokemus ei ole tarpeen. CoddyKitin C++ Academy-oppimispolku sopii vasta-alkajista edistyneisiin, joten voit aloittaa tästä tai alusta ja edetä omaan tahtiisi. Tämä on oppitunti 4/4.

Kuinka kauan ”Kutsuttavien olioiden valinta”-oppitunnin suorittaminen kestää?

Useimmat CoddyKitin oppitunnit kestävät noin 5–10 minuuttia. Jokainen oppitunti on lyhyt ja interaktiivinen, joten edistyt tasaisesti ja voit jatkaa siitä, mihin jäit – sekä verkossa että sovelluksessa.

Voinko kirjoittaa ja suorittaa koodia tällä C++ Academy-oppitunnilla?

Kyllä. Jokainen C++ Academy-oppitunti sisältää sisäänrakennetun koodieditorin, joten voit kirjoittaa ja suorittaa oikeaa koodia suoraan selaimessa ja saada välitöntä palautetta tekoälyltä – paikallista asennusta ei tarvita.

Kaikki tämän kurssin oppitunnit

  1. Funktio-osoittimet
  2. std::function
  3. std::bind
  4. Kutsuttavien olioiden valinta
← Takaisin: C++ Academy