Merhaba sevgili yazılımperver dostlarım. Yine bir haftalık C++ yazısı ile sizlerle birlikteyim. Bu yazımda sizler ile birlikte C++ 17 ile birlikte sunulmaya başlanan std::invoke() metoduna bir göz atacağız.
std::invoke() metodu <functional> kütüphanesi ile sunulmakta. Bu metot sayesinde farklı çağrılabilir nesneler (serbest fonksiyon işaretçileri, sınıf metodu işaretçileri, lambda metotları, fonksiyon nesneler), tek bir mekanizma ile çağrılabilecek. Bu sayede metot çağrılma mekanizması daha esnek ve standart bir şekilde gerçekleştirilebilecek. Peki bunları normalde nasıl yapıyorduk aşağıdaki kod örneğinde bunları görebilirsiniz.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 |
#include <iostream> #include <functional> using namespace std; // normal fonksiyon isaretcisi kullanimi // Ornek metodumuz int exampleSquare(int arg) { return arg*arg; } // Fonksiyon isaretcimizi tanimlayalim typedef int (*SquareFuncPtr)(int); // sinif metodu isaretcisi kullanimi class ExampleClass { public: int exampleSquare(int arg) { return arg*arg; } }; // Fonksiyon isaretcimizi tanimlayalim typedef int (ExampleClass::*MemberSquareFuncPtr)(int); int main() { // Normal fonksiyon isaretcisi kullanimi // C++ 17 oncesi kullanim SquareFuncPtr plainFuncPtr = &exampleSquare; cout << "Ilgili sayinin karesi: " << plainFuncPtr(2) << '\n'; // C++ 17 sonrasi kullanim cout << "Ilgili sayinin karesi: " << invoke(&exampleSquare, 2) << '\n'; // Sinif uyesi metot isaretcisi kullanimi ExampleClass classInstance; // C++ 17 oncesi kullanim MemberSquareFuncPtr memberFuncPtr = &ExampleClass::exampleSquare; cout << "Ilgili sayinin karesi: " << (classInstance.*memberFuncPtr)(3) << '\n'; // C++ 17 sonrasi kullanim cout << "Ilgili sayinin karesi: " << invoke(&ExampleClass::exampleSquare, classInstance, 3) << '\n'; return 0; } |
Yukarıdaki örnek kodta da görebileceğiniz üzere normal metotlar için geleneksel yöntem çok karmaşık olmasa da, özellikle sınıf üye metot işaretçileri işin içine girince karmaşıklık artıyor. Bunların yanında hem normal fonksiyon işaretçileri hem de sınıf metot işaretçileri ile çalışma ihtiyacınız olduğu durumda, her iki işi de kotarabilecek, basit ve anlaşılır bir arayüz sunuluyor.
Sizlerin de anlayacağı üzere, aslında bu metodun sunduğu yeteneği bir şekilde mevcut mekanizmalar ile (ilgili cpp referans sayfasında örneği var) gerçekleştirebiliyoruz. Tabiki bu std::invoke() kadar anlaşılabilir ve basit görünmüyor 🙂
Aşağıda bu metodun kullanımı ile ilgili referans kaynakta verilen örneği görebilirsiniz. Örnek içerisinde std::invoke()‘un kullanılabileceği olası durumlar güzel bir şekilde özetlenmiş.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 |
#include <functional> #include <iostream> struct Foo { Foo(int num) : num_(num) {} void print_add(int i) const { std::cout << num_+i << '\n'; } int num_; }; void print_num(int i) { std::cout << i << '\n'; } struct PrintNum { void operator()(int i) const { std::cout << i << '\n'; } }; int main() { // Serbest metot cagrilmasi std::invoke(print_num, -9); // Lambda cagrilmasi std::invoke([]() { print_num(42); }); // Sinif metodu cagrilmesi const Foo foo(314159); std::invoke(&Foo::print_add, foo, 1); // Sinif verisine erisim std::cout << "num_: " << std::invoke(&Foo::num_, foo) << '\n'; // Fonksiyon nesnesinin cagrilmesi std::invoke(PrintNum(), 18); } |
Yukarıdaki örneğe benzer bir şekilde özellikle “observer” ya da “callback” ya da “signal/slot” gibi mekanizmalar için de kullanışlı olabilir.