Yazılım geliştirmede deyimler: Yineleyici protokolü

Adanali

Active member
Yazılım geliştirmede deyimler: Yineleyici protokolü


  1. Yazılım geliştirmede deyimler: Yineleyici protokolü

Aralık tabanlı bir for döngüsünde kullanıcı tanımlı bir MyType veri türü kullanılacaksa, MyType, Iterator protokolünü uygulamalıdır.








Kullanıcı tanımlı bir veri türü, aralık tabanlı bir for döngüsünde kullanılmak üzere nasıl görünmelidir? Aşağıda bu sorunun en altına gideceğim.

Menzil tabanlı bir for döngüsü için gereksinimler


Basit bir e deneyi ile başlamak istiyorum. std::array C++ Insights’ta kullanın. İşte basit bir örnek:


// iteratorProtocol.cpp

#include <array>

int main() {

std::array<int, 5> myArr{1, 2, 3, 4, 5};
for (auto a: myArr) a;

}


Bundan, C++ Insights aşağıdaki kodu üretir:


#include <array>

int main()
{
std::array<int, 5> myArr = {{1, 2, 3, 4, 5}};
{
std::array<int, 5> & __range1 = myArr;
int * __begin1 = __range1.begin();
int * __end1 = __range1.end();
for(; __begin1 != __end1; ++__begin1) {
int a = *__begin1;
a;
}

}
return 0;
}


Daha genel bir ifadeyle: aralık tabanlı bir for döngüsü kullanılmalıdır (for(range_declaration : range_expression)), derleyici aşağıdaki kodu üretir:


{
auto && __range = range_expression ;
auto __begin = begin_expr;
auto __end = end_expr;
for (;__begin != __end; ++__begin) {
range_declaration = *__begin;
loop_statement
}
}


  • begin_expr VE end_expr: Bir yineleyici nesnesi döndürür
  • yineleyici nesne:
    • operator++: Yineleyiciyi artırın
    • operator*: Yineleyiciyi kaldırın ve geçerli öğeye erişin
    • operator!=: Yineleyiciyi başka bir yineleyici ile karşılaştırın
begin_expr VE end_expr önemli işlevleri çağırmak begin VE end İçinde range_expression AÇIK. begin VE end üye işlevler veya bağımsız işlevler olabilirler. range_expression Olmak.

Şimdi teoriyi uyguluyorum ve bir sayı üreteci yaratıyorum.

bir jeneratör


İlk uygulama yineleyici protokolünü destekler.

yineleyici protokolü


Aşağıdaki sınıf Generator temel yineleyici protokolünü destekler.


// iterator.cpp

#include <iostream>

class Generator {
int begin_{};
int end_{};

public:
Generator(int begin, int end) : begin_{begin}, end_{end} {}

class Iterator {
int value_{};
public:
explicit Iterator(int pos) : value_{pos} {}

int operator*() const { return value_; } // (3)

Iterator& operator++() { // (4)
++value_;
return *this;
}

bool operator!=(const Iterator& other) const { // (5)
return value_ != other.value_;
}
};

Iterator begin() const { return Iterator{begin_}; } // (1)
Iterator end() const { return Iterator{end_}; } // (2)
};

int main() {

std::cout << 'n';

Generator gen{100, 110};
for (auto v : gen) std::cout << v << " ";

std::cout << "nn";

}


Sınıf Generator üyelerin özelliklerine sahiptir. begin VE end (satır 1 ve 2) ile oluşturulan yineleyici nesneleri döndürür begin_ VE end_ başlatılır. begin_ VE end_ oluşturulan sayı aralığını temsil eder. İç sınıfı bana bırak Iterator üretilen sayıları kontrol edenleri analiz edin.

  • operator* geçerli değeri döndürür
  • operator++ mevcut değeri artırır
  • operator!= mevcut değeri ile karşılaştırın end_-Marka.
Bu, aşağıdaki program çıktısıyla sonuçlanır:








Tarafından oluşturulan yineleyiciyi istiyorum begin() VE end() döndürülür, genelleştirin ve ileri yineleyici yapın. Bundan sonra sınıf, Generator standart model kitaplığı algoritmalarının çoğunda kullanılır. Örneğin, ilişkisel kaplar bir ileri yineleyiciyi destekler.

ileri yineleyici


Aşağıdakiler iyileştirildi Generator bir iç sınıfa sahiptir Iteratorki bu bir ileri yineleyicidir.


// forwardIterator.cpp

#include <iostream>
#include <numeric>

class Generator {
int begin_{};
int end_{};

public:
Generator(int begin, int end) : begin_{begin}, end_{end} {}

class Iterator {
using iterator_category = std::forward_iterator_tag; // (1)
using difference_type = std::ptrdiff_t;
using value_type = int;
using pointer = int*;
using reference = int&;
int value_{};
public:
explicit Iterator(int pos) : value_{pos} {}

value_type operator*() const { return value_; }
pointer operator->() { return &value_; } // (2)

Iterator& operator++() {
++value_;
return *this;
}
Iterator operator++(int) { // (3)
Iterator tmp = *this;
++(*this);
return tmp;
}
// (4)
friend bool operator==(const Iterator& fir, const Iterator& sec) {
return fir.value_ == sec.value_;
}
friend bool operator!=(const Iterator& fir, const Iterator& sec) {
return fir.value_ != sec.value_;
}
};

Iterator begin() const { return Iterator{begin_}; }
Iterator end() const { return Iterator{end_}; }
};

int main() {

std::cout << 'n';

Generator gen{1, 11};
for (auto v : gen) std::cout << v << " "; // (5)

std::cout << "nn";
// (6)
std::cout << "sum: " << std::accumulate(std::begin(gen), std::end(gen), 0);

std::cout << "nn";
// (7)
std::cout << "prod: " << std::accumulate(gen.begin(), gen.end(), 1,
[](int fir, int sec){ return fir * sec; });

std::cout << "nn";

}


İlk ihtiyaçlar Iterator aşağıdaki üye işlev bildirimlerinde kullandığım bazı takma adlar. Programdaki önceki yineleyici uygulamasına ek olarak iterator.cpp geçerli yineleyici aşağıdaki üye işlevleri destekler: ok operatörü (operator-> 2. satırda), artırma sonrası operatör (operator++(int) 3. satırda) ve eşitlik operatörü (operator== 4. satırda).

Artık geliştirilmiş üreteç, döngü tabanlı bir aralıkta (satır 5) ve ayrıca STL algoritmasında kullanılabilir. std::accumulate. 6. satırdaki kod, 1’den 10’a kadar olan tüm sayıların toplamını hesaplar; 7. satırda benzer bir görev izler: burada 1’den 11’e kadar bir sayı çarpılır.İlk durumda toplama için nötr öğe 0’ı, ikinci durumda çarpma için nötr öğe 1’i seçiyorum.

Birinci ve ikinci invokasyon arasında ince bir fark vardır. std::accumulate. İlk çağrı, üye olmayan işlevleri kullanır std::begin VE std::end jeneratörün: std::accumulate(std::begin(gen), std::end(gen), 0)ancak ikinci çağrı doğrudan üye işlevlerini kullanır begin() VE end() uyguladığım jeneratörün.

Bu, aşağıdaki program çıktısıyla sonuçlanır:








Sıradaki ne?


Bir sonraki yazımda kovaryant dönüş tipini tanıtacağım. Bir üye işlevin kovaryant dönüş türü, bir üst üye işlevin daha kısıtlı bir tür döndürmesine izin verir. Bu, Prototip tasarım modelini uygularken özellikle kullanışlıdır.


(harita)



Haberin Sonu
 
Üst