Hello everybody, we are looking at another snippet this week. In this article, I will provide you a sample code that illustrate passing std::initializer_list as parameter. I already mentioned std::initializer_list in my modern C ++ article. If you don’t have any idea about this feature, I strongly recommend that you take a look at my article below.
Modern C++ (3): Uniform Initialization, override/final, default/delete, constexpr, vb.
Let assume that, we want to have a set of parameters of the same type in any method or constructor. We don’t want to use std::vector and similar containers (they don’t look so good 🙂 and we want to do this in a modern way. How are we going to do? Let’s see it 🙂
Our goal is to add points to this class (let’s assume that they are two-dimensional for now), in an easy way. Normally, you can add them individually or via a vector or array. Now let’s look at how we do this using std::initializer_list and how many different ways.
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 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 |
#include <iostream> #include <vector> #include <string> #include <initializer_list> struct Point2D { float mX; float mY; }; class LineString { public: LineString(const std::string& id) : mId{id} { std::cout << "Empty lineString [" << mId <<"] is constructed!" << '\n'; } // use of initializer_list as parameter for constructor LineString(const std::string& id, const std::initializer_list<Point2D>& input) : mId{id} , mPointList{input} { std::cout << "LineString [" << mId <<"] is constructed with following points: " << '\n'; // ranged loop kullanimi for(auto& point : input) { std::cout << "<" << point.mX << ", " << point.mY << ">\n"; } } // use of initializer_list as parameter for functions and how it can be used with ranged loops void addManyPointsRanged(const std::initializer_list<Point2D>& inputs) { for(auto& point : inputs) { mPointList.push_back(point); std::cout << "Point: " << point.mX << ", " << point.mY << " is added to [" << mId <<"]!\n"; } } // use of initializer_list as parameter for functions and how it can be used with iterators void addManyPointsByIterator(const std::initializer_list<Point2D>& inputs) { auto itr = inputs.begin(); while(itr != inputs.end()) { mPointList.push_back(*itr); std::cout << "Point: " << itr->mX << ", " << itr->mX << " is added to [" << mId <<"]!\n"; itr++; } } // you can also use initialize_list with operators LineString& operator+=(const std::initializer_list<Point2D> &list) { // std::vector insert() API also accept initializer_list, so let use that // we can also use this API in above method ;) mPointList.insert(mPointList.end(), list); for(auto& point : list) { std::cout << "Point: " << point.mX << ", " << point.mY << " is added to [" << mId <<"]!\n"; } return *this; } protected: std::string mId; std::vector<Point2D> mPointList; }; int main() { LineString tmp{"tmp"}; LineString tmp2{"tmp2", {{0, 0}, {10, 12}, {15, 20}}}; tmp2.addManyPointsRanged({{18, 22}, {34, 45}, {54, 63}, {65, 75}}); tmp2.addManyPointsByIterator({{0.5, 2.2}, {0.34, 5.7}, {3.4, 6.3}, {6.5, 8.9}}); tmp2 += {{11, 22}, {33, 44}, {55, 66}}; return 0; } |
Yes friends, I think the code above shows a lot of examples in the sense of the use of std::initializer_list. This kind of structures, I think, make the code really more readable and simple. That’s why I suggest you to start using it immediately.
I’m yazilimperver, see you in my next post. Happy codings 🙂
Modern C++ (3): Uniform Initialization, override/final, default/delete, constexpr, vb.
Şimdi diyelim ki herhangi bir metoda ya da yapıcıya aynı tipte bir takım parametreler geçirmek istiyoruz. std::vector ve benzeri konteynerler de kullanmak istemiyoruz (keza pek güzel durmuyorlar 🙂 ve bu işi modern bir şekilde yapmak istiyoruz. Nasıl yapacağız? Hemen bakalım 🙂
Örnek için LineString isminde bir sınıfımız olduğunu kabul edelim. Bu sınıf, noktaların birleşmesinden oluşan çizgileri temsil ettiğini düşünelim. Bu tarz geometriler özellikle Coğrafi Bilgi Sistemlerinde, vektörel verilerin temsil edilmesinde kullanılırlar. Aşağıda, farklı linestring geometrilerini görebilirsiniz:
Amacımız bu sınıfa noktaları (şimdilik iki boyutlu olduklarını kabul edelim), kolay bir şekilde eklemek olsun. Normal şartlarda bunları tek tek ya da bir vektör ya da dizi aracılığı ile ekleyebilirsiniz. Şimdi bunu std::initializer_list ile nasıl ve kaç farklı yolla yaparız ona bakalım.
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 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 |
#include <iostream> #include <vector> #include <string> #include <initializer_list> struct Point2D { float mX; float mY; }; class LineString { public: LineString(const std::string& id) : mId{id} { std::cout << "Empty lineString [" << mId <<"] is constructed!" << '\n'; } // initializer_list'in yapici ile kullanimi LineString(const std::string& id, const std::initializer_list<Point2D>& input) : mId{id} , mPointList{input} { std::cout << "LineString [" << mId <<"] is constructed with following points: " << '\n'; // ranged loop kullanimi for(auto& point : input) { std::cout << "<" << point.mX << ", " << point.mY << ">\n"; } } // initializer_list'in parametre olarak gecirilmesi ve ranged loop ile eklenmesi void addManyPointsRanged(const std::initializer_list<Point2D>& inputs) { for(auto& point : inputs) { mPointList.push_back(point); std::cout << "Point: " << point.mX << ", " << point.mY << " is added to [" << mId <<"]!\n"; } } // initializer_list'in parametre olarak gecirilmesi ve iterator ile eklenmesi void addManyPointsByIterator(const std::initializer_list<Point2D>& inputs) { auto itr = inputs.begin(); while(itr != inputs.end()) { mPointList.push_back(*itr); std::cout << "Point: " << itr->mX << ", " << itr->mX << " is added to [" << mId <<"]!\n"; itr++; } } // ayrica initialize_list'i atama operatoru ile de kullanabilirsiniz LineString& operator+=(const std::initializer_list<Point2D> &list) { // std::vector insert() API'si de initializer_list kabul ediyor // elbette bunu yukarida da kullanabilirdik mPointList.insert(mPointList.end(), list); for(auto& point : list) { std::cout << "Point: " << point.mX << ", " << point.mY << " is added to [" << mId <<"]!\n"; } return *this; } protected: std::string mId; std::vector<Point2D> mPointList; }; int main() { LineString tmp{"tmp"}; LineString tmp2{"tmp2", {{0, 0}, {10, 12}, {15, 20}}}; tmp2.addManyPointsRanged({{18, 22}, {34, 45}, {54, 63}, {65, 75}}); tmp2.addManyPointsByIterator({{0.5, 2.2}, {0.34, 5.7}, {3.4, 6.3}, {6.5, 8.9}}); tmp2 += {{11, 22}, {33, 44}, {55, 66}}; return 0; } |
Evet arkadaşlar, yukarıdaki kod sanırım std::initializer_list ‘in kullanımı anlamında bir çok örnek göstermiş oldu. Bu tarz yapılar, bana kalırsa kodu gerçekten daha okunabilir ve sade bir hale getiriyorlar. O sebeple şiddetle kullanmanızı öneriyorum.
Ben yazılımperver, bir sonraki yazımızda görüşmek üzere, iyi kodlamalar.