بخش ۱۷ - کتابخانه‌ی STL

در این بخش مثال‌هایی از استفاده از کتابخانه‌ی استاندارد STL مورد بررسی قرار می‌گیرند.

فهرست مثال‌ها

نوشتن عناصر بردار با تکرارکننده

در این مثال، عناصر یک بردار با استفاده از تکرارکننده پیمایش می‌شوند.

1_VectorIterator.cpp
#include <iostream>
#include <vector>
using namespace std;

int main() {
    vector<int> v;
    v.push_back(10);
    v.push_back(123);
    v.push_back(87);

    vector<int>::iterator it = v.begin();
    while (it != v.end()) {
        cout << *it << ' ';
        ++it;
    }
    cout << endl;

    for (vector<int>::iterator it2 = v.begin(); it2 != v.end(); ++it2)
        cout << *it2 << ' ';
    cout << endl;
}
				
تابع find

در این مثال، جستجو به دنبال یک عنصر در یک بردار توسط تابع find که در کتابخانه‌ی STL تعریف شده صورت می‌گیرد. همین تابع را برای یافتن یک کلمه در یک لیست پیوندی از رشته‌ها و یک عدد اعشاری در آرایه‌ای از اعداد نیز به‌کار خواهیم برد.

2_STLFind.cpp
#include <iostream>
#include <vector>
#include <string>
#include <list>
#include <algorithm>
using namespace std;

/*
template<typename I, typename T>
I find(I first, I last, const T& val) {
    while (first!=last && *first != val) 
        ++first;
    return first; 
}
*/

int main() {
    vector<int> v;
    v.push_back(10);
    v.push_back(123);
    v.push_back(87);

    vector<int>::iterator p = find(v.begin(), v.end(), 123);
    if (p != v.end())
        cout << "Found " << *p << endl;
    else
        cout << "Not found" << endl;

    list<string> words;
    words.push_back("Money");
    words.push_back("For");
    words.push_back("Nothing");

    list<string>::iterator q = find(words.begin(), words.end(), "Chicks");
    if (q != words.end())
        cout << "Found " << *q << endl;
    else
        cout << "Not found" << endl;

    double nums[] = {1.4, 50.1, 3.5};
    double *r = find(nums, nums + sizeof(nums)/sizeof(double), 50.1);
    if (r != nums + sizeof(nums)/sizeof(double))
        cout << "Found " << *r << endl;
    else
        cout << "Not found" << endl;
}
				
الگوی لیست پیوندی با تکرارکننده‌ی به سبک STL

در این مثال لیست پیوندی که در بخش ۱۵ نوشته شد را به تکرارکننده‌ای به سبک STL مجهز می‌کنیم. به این ترتیب از این لیست در بسیاری از الگوریتم‌های STL می‌شود استفاده کرد.

3_STLStyleIterator.cpp
#include <iostream>
#include <algorithm>
#include <numeric>
#include <vector>
#include <string>
using namespace std;

template<typename T>
class List {
private:
public:
    class Iterator : public iterator<input_iterator_tag, T> {
    private:
        Iterator(Node* n) { current = n; }
        friend class List;
    public:
        Iterator& operator++() { 
            if (current != NULL)
                current = current->next;
            return *this;
        }

        T& operator*() {
            return current->data;
        }

        bool operator==(const Iterator& it) {
            return current == it.current;
        }

        bool operator!=(const Iterator& it) {
            return current != it.current;
        }
    private:
        Node *current;
    };

};

int main() {
    List<int> l;
    
    l.push_back(86);
    l.push_front(43);
    l.push_front(12);
    
    cout << accumulate(l.begin(), l.end(), 0) << endl;

    List<int>::Iterator it = find(l.begin(), l.end(), 43);
    if (it != l.end()) {
        cout << "found\n";
        *it = 56;
    } else
        cout << "not found\n";

    vector<string> v;
    v.push_back("gholi");
    v.push_back("aroosi");
    v.push_back("naraft!");

    cout << accumulate(v.begin(), v.end(), string("")) << endl;
    
    double dd[3] = {1.2, 3.4, 67485.2};
    cout << accumulate(dd, dd + 3, 0.0) << endl;
}
				
مسندها و شیءتابع‌ها در STL

این مثال نحوه‌ی استفاده از تابع find_if در کتابخانه‌ی STL را نشان می‌دهد. این تابع در یک مجموعه از عناصر به دنبال اولین عنصری می‌گردد که «شرط خاصی» را ارضاء کند. این شرط ‏(که مسند یا predicate نام دارد) نامیده می‌شود، می‌تواند اشاره‌گر به تابع یا اصطلاحاً شیءتابع (function object) باشد که به معنی کلاسی است که عملگر پرانتز را سربارگذاری کرده است.

4_OddSelector.cpp
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;

/*
template<class In, class Pred>
In find_if(In first, In last, Pred pred) {
    while (first!=last && !pred(*first)) 
        ++first;
    return first; 
}
*/

bool odd(int x) { return x % 2; }

class OddSelector {
public:
    bool operator()(int x) { return x % 2; }
};

int main() {
    vector<int> v;
    v.push_back(10);
    v.push_back(39);
    v.push_back(42);

    vector<int>::iterator it = find_if(v.begin(), v.end(), odd);
    cout << *it << endl;

    vector<int>::iterator it2 = find_if(v.begin(), v.end(), OddSelector());
    cout << *it2 << endl;
}
				
استفاده‌ی پیشرفته‌تر از شیءتابع‌ها

این مثال، نشان می‌دهد استفاده از شیءتابع‌ها می‌تواند پیشرفته‌تر از مثال قبل باشد و شیء تابع مربوطه علاوه بر عملگر پرانتز اعضای دیگری هم داشته باشد. شیءتابع تعریف شده در این مثال، دانشجویان را بر اساس نمره cutoff فیلتر می‌کند. دقت کنید که اگر می‌خواستیم از اشاره‌گر به تابع استفاده کنیم لازم بود برای هر مقدار cutoff باید یک تابع مجزا می‌نوشتیم.

5_CutoffFuncObj.cpp
#include <iostream>
#include <vector>
using namespace std;

/*
template<class In, class Pred>
In find_if(In first, In last, Pred pred) {
    while (first!=last && !pred(*first)) 
        ++first;
    return first; 
}
*/

class student {
public:
    student(string n, double d) : name(n), grade(d) {}
    string get_name() const { return name; }
    double get_grade() const { return grade; }
private:
    string name;
    double grade;
};

class GradeBelow {
public:
    GradeBelow(double c) : cutoff(c) {}
    bool operator()(const student& s) {
        return s.get_grade() < cutoff;
    }
private:
    double cutoff;
};

int main() {
    vector<student> v;
    v.push_back(student("Moez", 8.0));
    v.push_back(student("Gholam", 17.3));
    v.push_back(student("Ghamar", 4.5));

    vector<student>::iterator it;
    it = find_if(v.begin(), v.end(), GradeBelow(10));
    cout << it->get_name() << endl;
    
    it = find_if(v.begin(), v.end(), GradeBelow(5));
    cout << it->get_name() << endl;
}