71 / 90

C++ Functors

C++ Funktorlar (Funksiya obyektlari)

C++ funktori (funksiya ob'ekti) - bu funksiya kabi chaqirilishi mumkin bo'lgan sinf yoki struktura ob'ekti.

U () funksiya chaqiruv operatorini haddan tashqari yuklaydi va bizga funksiya kabi ob'ektdan foydalanish imkonini beradi.

C++ da Funktor yarating

Biz C++ da funktor yaratishimiz mumkin:

example.cpp
class Greet {
  public:
    void operator()() {
      // funksiya tanasi
    }
};

Bu erda biz () funksiyasini chaqirish operatorini ortiqcha yuklaymiz. Bu bizga sinf ob'ektini quyida ko'rsatilgandek funksiya sifatida chaqirish imkonini beradi:

example.cpp
// Greet misolini yarating
Greet greet;

// ob'ektni funksiya sifatida chaqiring
greet();

[!NOTE] Sinf uchun () operatorini haddan tashqari yuklashda public kirish spetsifikatsiyasini o'rnatishni unutmang, chunki sukut bo'yicha sinf a'zolari private dir.

1-misol: C++ Funktor

example.cpp
#include <iostream>
using namespace std;

class Greet {

  public:    
    // haddan tashqari yuk funksiyasi chaqiruvi/qavslar operatori
    void operator()() {
      cout << "Hello World!";
    }
};

int main() {

  // Greet sinfining ob'ektini yarating
  Greet greet;

  // ob'ektni funksiya sifatida chaqiring
  greet();

  return 0;
}

Chiqish

kod
Hello World!

Yuqoridagi misolda biz C++ funktorlari yordamida Hello World! ni chop etuvchi oddiy dastur yaratdik.

Funktor yaratish uchun avvalo obyektini funksiya deb atashimiz mumkin bo‘lgan sinf yaratishimiz kerak. Shunday qilib, biz Greet nomli sinf yaratdik.

Greet sinfi ichida

Bu erda biz () funksiyasini chaqirish operatorini haddan tashqari yukladik:

example.cpp
class Greet {

public:
  // ortiqcha yuk funksiyasi chaqiruv operatori
  void operator()() {
    cout << "Hello World!";
  }
};

Bu yerda, bizning haddan tashqari yuklangan funksiya shunchaki Hello World! ni chop etadi.

Asosiy() funksiyasi ichida

Bu erda biz Greet sinfidan greet deb nomlangan ob'ektni yaratdik.

example.cpp
Greet greet;

Endi () operatori yordamida salomlashish obyektini chaqiramiz:

example.cpp
// "Salom dunyo!"
greet()

Shu bilan bir qatorda, salomlashishni quyidagi kod yordamida chaqirishimiz mumkin:

example.cpp
// "Salom dunyo!"
greet.operator()();

Qaytish turi va parametrlari bilan C++ Funktori

Parametrlarni qabul qiluvchi va qiymat qaytaruvchi funktorni ham belgilashimiz mumkin. Masalan,

example.cpp
#include <iostream>
using namespace std;

class Add {

  public:
    // ortiqcha yuk funksiyasi chaqiruv operatori
    // ikkita tamsayı argumentini qabul qiling
    // ularning summasini qaytaring
    int operator() (int a, int b) {
      return a + b;
    }
};

int main() {

  // Add sinfining ob'ektini yarating
  Add add;

  // qo'shish ob'ektiga qo'ng'iroq qiling
  int sum = add(100, 78);

  cout << "100 + 78 = " << sum;

  return 0;
}

Chiqish

kod
100 + 78 = 178

Yuqoridagi misolda biz ularning yig'indisini topish uchun butun sonni qaytarish turi va ikkita butun parametrli funktordan foydalanganmiz.

example.cpp
class Add {
  public:
    int operator()(int a, int b) {
      return a + b;
    }
};

main() ichida biz Add sinfidan qo'shish ob'ektini yaratdik.

Keyin, biz 100 va 78 parametrlari bilan add ob'ektini chaqirdik. Funktordan qaytariladigan qiymat sum o'zgaruvchisiga tayinlanadi.

example.cpp
// 178 ni qaytaradi
int sum = add(100, 78);

2-misol: a'zo o'zgaruvchiga ega C++ funktori

example.cpp
#include<iostream>
using namespace std;

class Add_To_Sum {

  private:
    int initial_sum;

  public:

    // 
    Add_To_Sum(int sum) {
      initial_sum = sum;
    }

    // ortiqcha yuk funksiyasi chaqiruv operatori
    int operator()(int num) {
      return initial_sum + num;
    }

};

int main() {

  // Add_To_Sum sinfining ob'ektini yarating
  // ob'ektning a'zo o'zgaruvchisini 100 qiymati bilan ishga tushiring
  Add_To_Sum add = Add_To_Sum(100);

  // qo'shish ob'ektini argument sifatida 78 bilan chaqiring
  int final_sum = add(78);

  cout << "100 + 78 = " << final_sum;

  return 0;
}

Chiqish

kod
100 + 78 = 178

Yuqoridagi misolda Add_To_Sum sinfida initial_sum a'zo o'zgaruvchisi mavjud. Biz ushbu o'zgaruvchini konstruktor yordamida ishga tushirdik:

example.cpp
// 
Add_To_Sum(int sum) {
  initial_sum = sum;
}

Keyin biz funksiyani chaqirish operatorini haddan tashqari yukladik:

  • boshlang'ich_sum o'zgaruvchisiga o'zining num parametrini qo'shadi
  • keyin natijani qaytaradi.
example.cpp
int operator()(int num) {
  return initial_sum + num;
}

main() da biz parametrlangan konstruktor yordamida add ob'ektining initial_sum o'zgaruvchisini 100 ga ishga tushirdik:

example.cpp
// initial_sum o'zgaruvchisini 100 ga ishga tushiring
Add_To_Sum add = Add_To_Sum(100);

Nihoyat, biz funktorni chaqirdik va argument sifatida 78 ni o'tkazdik.

example.cpp
// 100 va 78 summasini qaytaradi, ya'ni 178
int final_sum = add_to_100(78);

C++ Oldindan Aniqlangan Funktorlar

functional sarlavha faylini qo'shish orqali standart kutubxona tomonidan taqdim etilgan oldindan belgilangan funktorlardan foydalanishimiz mumkin:

example.cpp
#include <functional>

C++ arifmetik, relyatsion va mantiqiy amallar uchun quyidagi kutubxona funktorlarini taqdim etadi.

1. Arifmetik funksiyalar

Funktorlar tavsifi plus ikki parametrning yig‘indisini qaytaradi minus ikki parametrning farqini qaytaradi multiplies ikki parametrning mahsulotini qaytaradi divides ikkita parametrga bo‘lingandan so‘ng natijani qaytaradi modulus ikkita parametrga bo‘lingandan keyin qolganni qaytaradi negate a parametrining inkor etilgan qiymatini qaytaradi

2. Relyatsion funksiyalar

Funktorlar tavsifi equal_to true ni qaytaradi, agar ikkita parametr teng bo'lsa not_equal_to , agar ikkita parametr teng bo'lmasa, not_equal_to true ni qaytaradi, agar birinchi parametr ikkinchidan katta bo'lsa greater true ni qaytaradi, agar birinchi parametr ikkinchi parametrdan katta yoki unga teng bo'lsa, greater_equal true ni qaytaradi, agar birinchi parametr ikkinchidan katta yoki birinchi parametrdan kichik bo'lsa XCODEX ikkinchi parametrdan kichik bo'lsa. Agar birinchi parametr ikkinchidan kichik yoki unga teng bo'lsa, less_equal true ni qaytaradi

3. Mantiqiy funksiyalar

Funktorlar tavsifi logical_and ikkita mantiqiy qiymatning Mantiqiy VA ishlashi natijasini qaytaradi logical_or ikkita mantiqiy qiymatning Mantiqiy YOKI ishlashi natijasini qaytaradi logical_not mantiqiy EMAS mantiqiy natijasini qaytaradi

4. Bitli funksiyalar

Funktorlar tavsifi bit_and Bitwise VA ikkita parametrning ishlashi natijasini qaytaradi bit_or Bitwise OR ikki parametrning ishlashi natijasini qaytaradi bit_xor ikkita parametrning Bitwise XOR ishlashi natijasini qaytaradi

3-misol: STL bilan oldindan belgilangan C++ Funktor

Odatda funktorlar C++ STL bilan sort , count_if , all_of va boshqalar kabi STL algoritmlariga argument sifatida ishlatiladi.

Ushbu misolda biz oldindan belgilangan greater<T>() C++ funksiyasini ko'rib chiqamiz, bu erda T STL algoritmi sort bilan funktor parametrining turidir.

example.cpp
#include <iostream>
#include <algorithm>
#include <vector>
#include <functional>

using namespace std;

int main() {

  // int vektorini ishga tushirish
  vector<int> nums = {1, 20, 3, 89, 2};

  // vektorni kamayish tartibida tartiblang
  sort(nums.begin(), nums.end(), greater<int>());

  for(auto num: nums) {
    cout << num << ", ";
  }

  return 0;
}

Chiqish

kod
89, 20, 3, 2, 1

Yuqoridagi misolda biz butun sonlar vektorini (sonlar deb ataladi) kamayish tartibida tartiblash uchun oldindan belgilangan funktordan foydalanganmiz.

Odatiy bo'lib, sort() funksiyasi elementlarni o'sish tartibida tartiblaydi.

Uni kamayish tartibida tartiblash uchun biz oldindan belgilangan greater<T> funktoridan foydalandik.

example.cpp
sort(nums.begin(), nums.end(), greater<int>());

E'tibor bering, biz greater<int>() kodidan foydalanganmiz. Buning sababi, sonlar butun vektor, shuning uchun biz T o'rniga int dan foydalanamiz.

Nihoyat, biz for diapazoni yordamida tartiblangan vektorni chop etamiz.

Tez-tez so'raladigan savollar #include <iostream> using namespace std; struct Greet { // overload function call/parentheses operator void operator()() { cout << "Hello World!"; } }; int main() { // create a variable of Greet struct Greet greet; // call the struct variable as a function greet(); return 0; } chiqishi Salom dunyo! Yuqoridagi misolda biz Greet nomli struct yaratdik va Hello World! ni chop etish uchun () operatorini ortiqcha yukladik. main() da biz Greet o'zgaruvchisini yaratdik va () operatori yordamida funktorni chaqirdik: Greet greet; // Output: Hello World! greet(); #include <iostream> #include <vector> #include <algorithm> using namespace std; class Even_Counter { public: // overload function call operator // returns true if the n is even bool operator()(int n) { return n % 2 == 0; } }; int main() { // initialize vector of integers vector<int> nums = {1, 2, 3, 4, 5, 8, 10, 12}; // create an object of Even_Counter Even_Counter even_counter; // count the number of even numbers in the vector int even_count = count_if(nums.begin(), nums.end(), even_counter); cout << "There are " << even_count << " even numbers."; return 0; } Chiqish 5 ta juft son mavjud. Yuqoridagi misolda biz vector raqamlaridagi umumiy juft sonlarni hisoblash uchun count_if STL algoritmiga ega maxsus funktordan foydalandik. Biz Even_Counter nomli sinfni yaratdik va agar raqam juft bo'lsa, true ni qaytarish uchun funksiya chaqiruvi operatorini ortiqcha yukladik. bool operator()(int n) { return n % 2 == 0; } main() da biz nums nomli vector butun sonini va even_counter nomli Even_Counter obyektini yaratdik. Keyin, sonlarda juft butun sonlar sonini hisoblash uchun count_if algoritmidan foydalanamiz: int even_count = count_if(nums.begin(), nums.end(), even_counter); count_if ga uchinchi argument sifatida even_counter funktorini o'tkazganimizga e'tibor bering. even_counter funktori joriy vektor elementni n argumenti sifatida qabul qiladi va agar n juft bo'lsa, true ni qaytaradi. Funksiyani chaqirish operatorini tur parametrlari bilan ortiqcha yuklash orqali umumiy funktor yaratishimiz mumkin. Buning uchun biz class templates dan foydalanishimiz kerak. #include <iostream> #include <algorithm> #include <vector> using namespace std; template<typename T> class Greater_Than { public: // returns true if left is greater than right bool operator()(const T &left, const T &right) { return left > right; } }; int main() { // initialize vector of int vector<int> int_nums = {1, 20, 3, 89, 2}; // sort the vector in descending order sort(int_nums.begin(), int_nums.end(), Greater_Than<int>()); for(auto num: int_nums) { cout << num << ", "; } return 0; } Chiqish 89, 20, 3, 2, 1 Yuqoridagi misolda biz C++ da oldindan belgilangan greater<int> funksiyasiga o'xshash ishlaydigan Greater_Than<T> funktorini joriy qildik. Odatiy bo'lib, STL sort() funksiyasi elementlarni o'sish tartibida tartiblaydi. Inside Greater_Than Class: template<typename T> class Greater_Than { public: bool operator()(const T &left,const T &right) { return left > right; } }; Inside main() Funksiya: Biz int_nums butun vektorini ishga tushirdik. Keyin vektorni STL sort() funksiyasidan foydalanib tartiblaymiz. // vektorni kamayish tartibida tartiblash sort(int_nums.begin(), int_nums.end(), Katta_tana<int>()); E'tibor bering, biz Greater_Than sinfining ob'ektini yaratmadik, lekin Greater_Than<int>() ni funksiya ob'ektini yaratuvchi uchinchi argument sifatida topshirdik. Bu quyidagilarga teng: Greater_Than<int> greater_than; // sort the vector in descending order sort(int_nums.begin(), int_nums.end(), greater_than);