Functional (C++)

**Functional**, C++, լեզվի Ստանդարտ գրադարանի վերնագրային ֆայլ, որը իրենից ներկայացնում է կաղապարների հավաքածու ֆունկցիոնալ օբյեկտների հետ աշխատելու համար, ինչպես նաև օգնական դասերի հավաքածու՝ ստանդարտ գրադարանի ալգորիթմներում օգտագործելու համար։

## Պատմություն
Առաջին  վերնագրային ֆայլն առաջացել է 1998 թվականին։ Ի սկզբանե նրա մեջ մտցրել են օժանդակ ֆունկցիոնալ օբյեկտներ, որպեսզի ավելի հեշտ օգտագործել STL։ Ինչպես նաև այստեղ են ներառվել կապողական (binders) և փաթաթողական ֆունկցիաներ, որոնց նպատակն էր հեշտացվել աշխատանքը, երբ ակտիվորեն օգտագործվում էր ցուցիչների փոխանցումը ֆունկցիաներին, այսինքն, երբ աշխատանք են կատարում ֆունկցիաների հետ։
Վերնագրային ֆայլերի Էական փոփոխություններ կատարվեց С++ TR1 ընդարձակման գրադարանում
։ Boost գրադարանից STL են տեղափոխել function, bind, mem_fn, result_of, reference_wrapper, hash դասերը։ Այդ փոփոխությունների մեծամասնությունը, բացառությամբ result_of-ի ընդգրկվեց այդ պահին օգտագործվող C++11 ստանդարտ լեզվի մեջ։ Քանի որ function-ը և bind-ը մեծ մասամբ կրկնօրինակում է 1998-ի ստանդարտի կապող ու փաթաթող ֆունկցիաներին, С++11-ում այդ ֆունկցիաները անվանված են հնացած (deprecated)։

## Ընդհանուր հասկացություններ
### Ստանդարտի տերմինները
C++11 լեզվում օգտագործվում են  վերնագրային ֆայլին վերաբերվող հետևյալ տերմինները՝
* **Ֆունկցիայի օբյեկտի տեսակ** (function object type)՝ փոստիֆիկ արտահայտություն ֆունկցիա կանչի ժամանակ, որտեղ փոստիֆիկ արտահայտությունը գերբեռնված ֆունկցիաների կամ կաղապարների կամ հասցեների հավաքածու է։
* **Զանգի ձև** (call signature) այս անվանումից հետո դրվում է Կլոր փակագծեր, որի մեջ գրվում է զրոների հերթականություն։
* **Կանչված տեսակ** (callable type)՝ ֆունկցիոնալ տիպի օբյեկտ կամ դասի անդամի ցուցիչ։
* **Կանչված օբյեկտ** (callable object) ՝ կանչված տեսակի օբյեկտ։
* **Կանչի օբյեկտի տեսակ** (call wrapper type) ` տիպ է, որը պարունակում է կանչվող օբյեկտ և աջակցում է կանչի գործողությանը, որը տանում է պահպանված օբյեկտի կանչին (invoke)։
* **Կանչի օբյեկտ** (call wrapper)՝ փաթաթող կանչ տեսակի օբյեկտ։
* **Նպատկի օբյեկտ** (target object)՝ կանչված օբյեկտ, որը պարունակում է կանչի օբյեկտ։

### Ֆունկցիոնալ օբյեկտի հասկացություն
Ֆունկցիոնալ օբյեկտը դաս է որոշակի կանչի ֆունկցիայի օպերատորով՝ operator ()։ Հետևյալ կոդի մեջ

```cpp
FunctionObjectType func;
func();
```

func() արտահայտությունը համարվում է func ֆունկցիոնալ օբյեկտի կանչ, այլ ոչ թե որևէ ֆունկիայի կանչ, որի անունը func է։ Ֆունկցիոնալ օբյեկտի ձևը պետք է լինի հետևյալ կերպ՝

```cpp
class FunctionObjectType {
  public:
  void operator() () {
    // Do some work
  }
};
```

Մինչև ֆունկցիայի օգտագործումը ֆունկցիոնալ օբյեկտները ունեն մի շարք առավելություններ։ Դրանցից են՝
# Կարող է լինել երկու օբյեկտ նույն ֆունկցիոնալ տեսկի, բայց միևնույն ժամանակ գտնվեն տարբեր իրավիճակներում, որը հնարավոր չէ սովորական ֆունկցիաների ժամանակ։ Նաև ֆունկցիոնալ օբյեկտները կարող են տրամադրել նախնական տվյալների կարգավորման ծրագիր։
# Յուրաքանչյուր ֆունկցիոնալ օբյեկտ ունի իր տեսակը, հետևաբար կա հնարավորություն փոխանցել այդ տեսակը որպես կաղապարի պարամետր, որպեսզի նշի որոշակի վարքագիծ։ Օրինակ՝ կոնտեյների տեսակները տարբեր ֆունկցիոնալ օբեյկներով տարբերվում են։
# Օբյեկտ-ֆունկցիաները ավելի արագ են կատարվում քան ֆունկցիաների ցուցիչները։ Օրինակ՝ կառուցել (inline) դիմումը () դասի օպերատորին ավելի հեշտ քան ֆունկցիայի, որը փոխանցվել է ցուցչով։.

### Պրեդիկատներ
Ֆունկցիոնակ օբյեկտները, որոնք վերադարձնում են բուլյան տեսակ անվանում են *[[պրեդիկատ]]ներ*։ Ստանդարտ գրադարանում օգտագործում են ունար և բինար պրեդիկատներ։ Պրեդիկատի գործողությունները կախված չէ կատարվող գործողության պատճենման քանակից, քանի որ С++ ստանդարտը չի հաշվում, թե քանի անգամ է պատճենվել ալգորիթմը օգտագործման ժամանակ։

## Փաթեթավորող գործառույթներ
### std::function
C++11 ստանդարտից սկսած std::function կաղապարային դասը համարվում է պոլիմորֆիզմ ֆունկցիայի փաթեթ ընդհանուր օգտագործման համար։ std::function դասի օբյեկտները կարող են պահել, պատճենել և կանչել կամայական *անհրաժեշտ օբյեկտներ* ՝ ֆունկցիա, լյամբդա-արտահայտություն և այլ ֆունկցիոնալ օբյեկտներ։ Ընդհանուր ասած, կամայական տեղ, որտեղ պետք է օգտագործել ֆունկցիայի ցուցիչը՝ կանչը չեղարկելու համար կամ հետ կանչի ֆունկցիա ստեղծելու համար օգտագործվում է std::function ֆունկցիան։

Առաջին անգամ տվյալ ֆունկցիան հայտնվել է Function գրադարանում Boost 1.23.0 տարբերակի ժամանակ։ Հետագա զարգացման ժամանակայն այն ներառվել է C++ TR1-ու և С++11-ում։

#### Դասի որոշումը

```cpp
template<class> class function; // undefined
template<class R, class... ArgTypes> class function<R(ArgTypes...)>;
```

Ստանդարտում կան նաև օժանդակ բաղադրիչներ՝ swap и assign և համեմատության օպերատորներ՝ (== и !=), nullptr-ի հետ միասին։

#### Օգտագործման օրինակը

```cpp
#include <iostream>
#include <functional>

struct A {
    A(int num) : num_(num){}
    void printNumberLetter(char c) const {std::cout << "Number: " << num_  << " Letter: " << c << std::endl;}
    int num_;
};

void printLetter(char c)
{
    std::cout << c << std::endl;
}

struct B {
    void operator() () {std::cout << "B()" << std::endl;}
};

int main()
{
    // Ֆունկցիա
    std::function<void(char)> f_print_Letter = printLetter;
    f_print_Letter('Q');

    // Լյամբդա-արտահայտություն։
    std::function<void()> f_print_Hello = [] () {std::cout << "Hello world!" << std::endl;};
    f_print_Hello();

    // Կապիչ։
    std::function<void()> f_print_Z = std::bind(printLetter, 'Z');
    f_print_Z();

    // Դասի կանչ։
    std::function<void(const A&, char)> f_printA = &A::printNumberLetter;
    A a(10);
    f_printA(a, 'A');

    // Ֆունկցիոնալ օբյեկտ։
    B b;
    std::function<void()> f_B = b;
    f_B();
}
```

Վերևում գրված կոդի արդյունքը՝

```cpp
Q
Hello world!
Z
Number: 10 Letter: A
B()
```


#### std::bad_functional_call
Բացառություն bad_functional_call տիպը կանտեսվի function::operator() ֆունցիայի փաթեթում թիրախի բացակայության դեպքում։ bad_functional_call ֆունկցիան եկել է std::exception ֆունկցիայից և նրա մեջ կա վիրտուալ what() տարբերակը տեքստի սխալը գտնելու համար։ Օգտագործման օրինակը՝

```cpp
#include <iostream>
#include <functional>

int main()
{
    std::function<void()> func = nullptr;
    try {
        func();
    } catch(const std::bad_function_call& e) {
        std::cout << e.what() << std::endl;
    }
}
```


### std::mem_fn
std::mem_fn կաղապարային ֆունկցիան ստեղծում է փաթեթող օբյեկտ դասի անդամների շուրջը։ Այդ օբյեկտը կարող է պահել, պատճենել և կանչել դասի անդամին։.

Առաջին անգամ std::mem_fn կաղապարային ֆունկցիան հայտնվել է Member Function գրադարանում (Boost 1.25.0 տարբերակով)։ Այն նույնպես ներառվել է C++ TR1-ում և С++11-ում։ Boost գրադարանում այն կատարելագործվում էր, որպես std::mem_fun и std::mem_fun_ref ստանդարտ ֆունկցիաների ընդհանրացում։

## Ֆունկցիոնալ օբյեկտներ
Նախօրոք որոշված հիմնական հոդվածների համար նախատեսված ֆունկցիոնալ օբյեկտների հավաքածուն, կաղապարների ստանդարտ գրադարանի անբաժան մասն էր կազմում։ Նրանց մեջ մտնում էին թվաբանական գոծողություններ (+-*/%), հիմնական տրամաբանական գործողությունները (&&, ||, !) և համեմատման գործողությունները (==, !=, >, =, )։ Տրամաբանական և համեմատության գործողությունները համարվում են հաստատուններ և վերադարձնում են բուլյան տեսակը։ С++11-ից սկսած ավելացել են որոշ բիտային գործողություններ (and, or, xor, not)։

## Փաթեթների հղումներ
 վերնագրային ֆայլում կա օգնող std::reference_wrapper դաս, որն ինքնըստինքյան տալիս է օբյեկտի հղում կամ ֆունկցիայի հղում, որը փոխանցվել էր նրան կաղապարով։ reference_wrapper ֆունկցիան իմաստը կայնում է նրանում, որ պահպանել հղումները, որը փոխանցվել էր T տեսակի կաղապներում և արտածել այն երբ դիմում ենք operator T& ()-ին։

Առաջին անգամ reference_wrapper կաղապարային դասը հայտնվել է Ref գրադարանում (Boost 1.25.0 տարբերակի մեջ)։ որոշ բերելավումներից հետո նա ավելացվել է С++11 մեջ։

reference_wrapper օբյեկտներ ստեղծելու համար տրված են օգնական ref և cref ֆունկցիաներ։ Որոշված են հետևյալ կերպ՝

```cpp
template <class T> reference_wrapper<T> ref(T& t) noexcept;
template <class T> reference_wrapper<const T> cref(const T& t) noexcept;
```


## Տես նաև
* C++
* C++11
* C++ լեզվի ստանդարտ գրադարան

## Ծանոթագրություններ

Կատեգորիա:1998 հիմնադրումներ