Functional (C++)
Functional, C++, լեզվի Ստանդարտ գրադարանի վերնագրային ֆայլ, որը իրենից ներկայացնում է կաղապարների հավաքածու ֆունկցիոնալ օբյեկտների հետ աշխատելու համար, ինչպես նաև օգնական դասերի հավաքածու՝ ստանդարտ գրադարանի ալգորիթմներում օգտագործելու համար։
Պատմություն
[խմբագրել | խմբագրել կոդը]Առաջին <functional> վերնագրային ֆայլն առաջացել է 1998 թվականին[1]։ Ի սկզբանե նրա մեջ մտցրել են օժանդակ ֆունկցիոնալ օբյեկտներ, որպեսզի ավելի հեշտ օգտագործել STL։ Ինչպես նաև այստեղ են ներառվել կապողական (binders) և փաթաթողական ֆունկցիաներ, որոնց նպատակն էր հեշտացվել աշխատանքը, երբ ակտիվորեն օգտագործվում էր ցուցիչների փոխանցումը ֆունկցիաներին, այսինքն, երբ աշխատանք են կատարում ֆունկցիաների հետ[2]։ Վերնագրային ֆայլերի Էական փոփոխություններ կատարվեց С++ TR1 ընդարձակման գրադարանում[3] ։ Boost գրադարանից STL են տեղափոխել function, bind, mem_fn, result_of, reference_wrapper, hash դասերը։ Այդ փոփոխությունների մեծամասնությունը, բացառությամբ result_of-ի ընդգրկվեց այդ պահին օգտագործվող C++11 ստանդարտ լեզվի մեջ[4]։ Քանի որ function-ը և bind-ը մեծ մասամբ կրկնօրինակում է 1998-ի ստանդարտի կապող ու փաթաթող ֆունկցիաներին, С++11-ում այդ ֆունկցիաները անվանված են հնացած (deprecated)։
Ընդհանուր հասկացություններ
[խմբագրել | խմբագրել կոդը]Ստանդարտի տերմինները
[խմբագրել | խմբագրել կոդը]C++11 լեզվում օգտագործվում են <functional> վերնագրային ֆայլին վերաբերվող հետևյալ տերմինները՝
- Ֆունկցիայի օբյեկտի տեսակ (function object type)՝ փոստիֆիկ արտահայտություն ֆունկցիա կանչի ժամանակ, որտեղ փոստիֆիկ արտահայտությունը գերբեռնված ֆունկցիաների կամ կաղապարների կամ հասցեների հավաքածու է։
- Զանգի ձև (call signature) այս անվանումից հետո դրվում է Կլոր փակագծեր, որի մեջ գրվում է զրոների հերթականություն։
- Կանչված տեսակ (callable type)՝ ֆունկցիոնալ տիպի օբյեկտ կամ դասի անդամի ցուցիչ։
- Կանչված օբյեկտ (callable object) ՝ կանչված տեսակի օբյեկտ։
- Կանչի օբյեկտի տեսակ (call wrapper type) ` տիպ է, որը պարունակում է կանչվող օբյեկտ և աջակցում է կանչի գործողությանը, որը տանում է պահպանված օբյեկտի կանչին (invoke)։
- Կանչի օբյեկտ (call wrapper)՝ փաթաթող կանչ տեսակի օբյեկտ։
- Նպատկի օբյեկտ (target object)՝ կանչված օբյեկտ, որը պարունակում է կանչի օբյեկտ։
Ֆունկցիոնալ օբյեկտի հասկացություն
[խմբագրել | խմբագրել կոդը]Ֆունկցիոնալ օբյեկտը դաս է որոշակի կանչի ֆունկցիայի օպերատորով՝ operator ()։ Հետևյալ կոդի մեջ
FunctionObjectType func;
func();
func() արտահայտությունը համարվում է func ֆունկցիոնալ օբյեկտի կանչ, այլ ոչ թե որևէ ֆունկիայի կանչ, որի անունը func է։ Ֆունկցիոնալ օբյեկտի ձևը պետք է լինի հետևյալ կերպ՝
class FunctionObjectType {
public:
void operator() () {
// Do some work
}
};
Մինչև ֆունկցիայի օգտագործումը ֆունկցիոնալ օբյեկտները ունեն մի շարք առավելություններ[5]։ Դրանցից են՝
- Կարող է լինել երկու օբյեկտ նույն ֆունկցիոնալ տեսկի, բայց միևնույն ժամանակ գտնվեն տարբեր իրավիճակներում, որը հնարավոր չէ սովորական ֆունկցիաների ժամանակ։ Նաև ֆունկցիոնալ օբյեկտները կարող են տրամադրել նախնական տվյալների կարգավորման ծրագիր։
- Յուրաքանչյուր ֆունկցիոնալ օբյեկտ ունի իր տեսակը, հետևաբար կա հնարավորություն փոխանցել այդ տեսակը որպես կաղապարի պարամետր, որպեսզի նշի որոշակի վարքագիծ։ Օրինակ՝ կոնտեյների տեսակները տարբեր ֆունկցիոնալ օբեյկներով տարբերվում են։
- Օբյեկտ-ֆունկցիաները ավելի արագ են կատարվում քան ֆունկցիաների ցուցիչները։ Օրինակ՝ կառուցել (inline) դիմումը () դասի օպերատորին ավելի հեշտ քան ֆունկցիայի, որը փոխանցվել է ցուցչով[6]։.
Պրեդիկատներ
[խմբագրել | խմբագրել կոդը]Ֆունկցիոնակ օբյեկտները, որոնք վերադարձնում են բուլյան տեսակ անվանում են պրեդիկատներ։ Ստանդարտ գրադարանում օգտագործում են ունար և բինար պրեդիկատներ։ Պրեդիկատի գործողությունները կախված չէ կատարվող գործողության պատճենման քանակից, քանի որ С++ ստանդարտը չի հաշվում, թե քանի անգամ է պատճենվել ալգորիթմը օգտագործման ժամանակ։
Փաթեթավորող գործառույթներ
[խմբագրել | խմբագրել կոդը]std::function
[խմբագրել | խմբագրել կոդը]C++11 ստանդարտից սկսած std::function կաղապարային դասը համարվում է պոլիմորֆիզմ ֆունկցիայի փաթեթ ընդհանուր օգտագործման համար։ std::function դասի օբյեկտները կարող են պահել, պատճենել և կանչել կամայական անհրաժեշտ օբյեկտներ ՝ ֆունկցիա, լյամբդա-արտահայտություն և այլ ֆունկցիոնալ օբյեկտներ։ Ընդհանուր ասած, կամայական տեղ, որտեղ պետք է օգտագործել ֆունկցիայի ցուցիչը՝ կանչը չեղարկելու համար կամ հետ կանչի ֆունկցիա ստեղծելու համար օգտագործվում է std::function ֆունկցիան։
Առաջին անգամ տվյալ ֆունկցիան հայտնվել է Function գրադարանում Boost 1.23.0 տարբերակի ժամանակ[7]։ Հետագա զարգացման ժամանակայն այն ներառվել է C++ TR1-ու և С++11-ում։
Դասի որոշումը
[խմբագրել | խմբագրել կոդը]template<class> class function; // undefined
template<class R, class... ArgTypes> class function<R(ArgTypes...)>;
Ստանդարտում կան նաև օժանդակ բաղադրիչներ՝ swap и assign և համեմատության օպերատորներ՝ (== и !=), nullptr-ի հետ միասին։
Օգտագործման օրինակը
[խմբագրել | խմբագրել կոդը]#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();
}
Վերևում գրված կոդի արդյունքը՝
Q
Hello world!
Z
Number: 10 Letter: A
B()
std::bad_functional_call
[խմբագրել | խմբագրել կոդը]Բացառություն bad_functional_call տիպը կանտեսվի function::operator() ֆունցիայի փաթեթում թիրախի բացակայության դեպքում։ bad_functional_call ֆունկցիան եկել է std::exception ֆունկցիայից և նրա մեջ կա վիրտուալ what() տարբերակը տեքստի սխալը գտնելու համար։ Օգտագործման օրինակը՝
#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 կաղապարային ֆունկցիան ստեղծում է փաթեթող օբյեկտ դասի անդամների շուրջը։ Այդ օբյեկտը կարող է պահել, պատճենել և կանչել դասի անդամին[8]։.
Առաջին անգամ std::mem_fn կաղապարային ֆունկցիան հայտնվել է Member Function գրադարանում (Boost 1.25.0 տարբերակով)[7]։ Այն նույնպես ներառվել է C++ TR1-ում և С++11-ում։ Boost գրադարանում այն կատարելագործվում էր, որպես std::mem_fun и std::mem_fun_ref ստանդարտ ֆունկցիաների ընդհանրացում։
Ֆունկցիոնալ օբյեկտներ
[խմբագրել | խմբագրել կոդը]Նախօրոք որոշված հիմնական հոդվածների համար նախատեսված ֆունկցիոնալ օբյեկտների հավաքածուն, կաղապարների ստանդարտ գրադարանի անբաժան մասն էր կազմում[2]։ Նրանց մեջ մտնում էին թվաբանական գոծողություններ (+-*/%), հիմնական տրամաբանական գործողությունները (&&, ||, !) և համեմատման գործողությունները (==, !=, >, <, >=, <=)։ Տրամաբանական և համեմատության գործողությունները համարվո��մ են հաստատուններ և վերադարձնում են բուլյան տեսակը։ С++11-ից սկսած[4] ավելացել են որոշ բիտային գործողություններ (and, or, xor, not)։
տեսակ | անվանում | գործողությունների քանակ | վերադարձնող տեսակ | գործողություն |
---|---|---|---|---|
Համեմատում | equal_to | Բինար | bool | x == y |
not_equal_to | Բինար | bool | x != y | |
greater | Բինար | bool | x > y | |
less | Բինար | bool | x < y | |
greater_equal | Բինար | bool | x >= y | |
less_equal | Բինար | bool | x <= y | |
Логические | logical_and | Բինար | bool | x && y |
logical_or | Բինար | bool | x || y | |
logical_not | Ունար | bool | !x | |
Թվաբանական | plus | Բինար | T | x + y |
minus | Բինար | T | x - y | |
multiplies | Բինար | T | x * y | |
divides | Բինար | T | x / y | |
modulus | Բինար | T | x % y | |
negate | Ունար | T | -x | |
Բիտային (C++11) | bit_and | Բինար | T | x & y |
bit_or | Բինար | T | x | y | |
bit_xor | Բինար | T | x ^ y | |
bit_not | Ունար | T | ~x |
Փաթեթների հղումներ
[խմբագրել | խմբագրել կոդը]<functional> վերնագրային ֆայլում կա օգնող std::reference_wrapper դաս, որն ինքնըստինքյան տալիս է օբյեկտի հղում կամ ֆունկցիայի հղում, որը փոխանցվել էր նրան կաղապարով։ reference_wrapper ֆունկցիան իմաստը կայնում է նրանում, որ պահպանել հղումները, որը փոխանցվել էր T տեսակի կաղապներում և արտածել այն երբ դիմում ենք operator T& ()-ին։
Առաջին անգամ reference_wrapper կաղապարային դասը հայտնվել է Ref գրադարանում (Boost 1.25.0 տարբերակի մեջ)[7]։ որոշ բերելավումներից հետո նա ավելացվել է С++11 մեջ։
reference_wrapper օբյեկտներ ստեղծելու համար տրված են օգնական ref և cref ֆունկցիաներ։ Որոշված են հետևյալ կերպ՝
template <class T> reference_wrapper<T> ref(T& t) noexcept;
template <class T> reference_wrapper<const T> cref(const T& t) noexcept;
Տես նաև
[խմբագրել | խմբագրել կոդը]Ծանոթագրություններ
[խմբագրել | խմբագրել կոդը]- ↑ «Programming languages - C++» (անգլերեն). ISO/IEC 14882. 1998 թ․ ապրիլի 23. Արխիվացված է օրիգինալից 2013 թ․ մայիսի 17-ին. Վերցված է 2013 թ․ մայիսի 1-ին.
- ↑ 2,0 2,1 Alexander Stepanov and Meng Lee (1995 թ․ նոյեմբերի 14). «The Standard Template Library» (PDF) (անգլերեն). HP Laboratories Technical Report 95-11(R.1). Արխիվացված (PDF) օրիգինալից 2013 թ․ մայիսի 17-ին. Վերցված է 2013 թ․ մայիսի 1-ին.
- ↑ (2005-06-24)։ «Draft Technical Report on C++ Library Extensions»։ ISO/IEC JTC1/SC22/WG21։ Վերցված՝ 2013-05-01։
- ↑ 4,0 4,1 «ISO/IEC 14882:2011». ISO. 2011 թ․ սեպտեմբերի 2. Արխիվացված օրիգինալից 2013 թ․ մայիսի 17-ին. Վերցված է 2013 թ․ մայիսի 2-ին.
- ↑ Josuttis, Nicolai M. (2012). The C++ standard library : a tutorial and reference. Addison-Wesley. ISBN 0-321-62321-5.
- ↑ Stroustrup, Bjarne (2000). The C++ Programming Language: Special Edition. Addison-Wesley. ISBN 0-201-70073-5.
- ↑ 7,0 7,1 7,2 «Boost Library Documentation» (անգլերեն). Արխիվացված օրիգինալից 2013 թ․ մայիսի 17-ին. Վերցված է 2013 թ․ մայիսի 1-ին.
- ↑ «Boost Library Documentation : mem_fn.hpp» (անգլերեն). Արխիվացված օրիգինալից 2013 թ․ մայիսի 17-ին. Վերցված է 2013 թ․ մայիսի 2-ին.