Yazılımın geliştirilmesinde salak: Yineleyici protokolü
Bir tür kişiselleştirilmiş mira verisi aralık tabanlı bir döngüde kullanılması gerekiyorsa, MyType yineleyici protokolünü uygulamalıdır.
Bir döngüde aralığa dayalı olarak kullanılabilmesi için kişiselleştirilmiş bir veri türü nasıl elde edilmelidir? Bu sorunun dibine gidiyorum.
Döngü tabanlı bir aralık için gereksinimler
Basit bir deneyle başlamak istiyorum ve std::array C ++ 'da içgörü 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;
}
C ++ Insights aşağıdaki kodu oluşturur:
#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 olarak formüle edildi: Aralık tabanlı bir döngü kullanılmalıdır (for(range_declaration : range_expression)), derleyici aşağıdaki kodu oluşturur:
{
auto && __range = range_expression ;
auto __begin = begin_expr;
auto __end = end_expr;
for (;__begin != __end; ++__begin) {
range_declaration = *__begin;
loop_statement
}
}
Şimdi teoriyi çeviriyorum ve bir sayı jeneratörü 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 Üye işlevleri var begin VE end (Satır 1 ve 2), yineleme nesnelerini şöyle döndür begin_ VE end_ başlatılırlar. begin_ VE end_ Kendinizi üretilen sayılar alanına koyun. Bana iç sınıfı bırak Iterator Oluşturulan sayıları kontrol ettiğini analiz edin.
Yineleyiciyi istiyorum begin() VE end() İade edilir, genelleştirilir ve onu bir yayıncı ileriye götürür. Yani sınıf yapabilir Generator Standart model kitaplığın çoğu algoritmalarında. Örneğin, ilişkisel kaplar ileri bir düzenleyiciyi destekler.
İleri bir yayıncı
Aşağıdaki gelişti Generator bir iç sınıfı var IteratorBu ileri bir yayıncı.
// 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:
trdiff_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 İhtiyaçlar Iterator Üyenin işlevlerinin aşağıdaki beyanlarında kullandığım bazı aliase. Programdaki yineleyicinin önceki uygulamasına ek olarak iterator.cpp Mevcut yineleyici, üyenin aşağıdaki işlevlerini destekler: PFEIL operatörü (operator-> 2. satırda), açma sonrası operatör (operator++(int) 3. satırda) ve eşitlik operatörü (operator== 4. satırda).
Şimdi geliştirilmiş jeneratör aralık tabanlı bir döngüde (satır 5), aynı zamanda STL algoritmasında da kullanılabilir std::accumulate. Satır 6'daki kod, 1'den 10'a kadar tüm sayıların toplamını hesaplar; Benzer bir görev satır 7'de izlenir: 1 ila 11 arasında bir sayı burada çarpılır. İlk durumda, toplam için nötr eleman 0'ı seçiyorum, ikinci durumda çarpma için nötr element 1.
Birinci ve ikinci çağrı arasında güzel bir fark var 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ı, üyenin işlevlerini doğrudan kullanır begin() VE end() uyguladığım jeneratörün.
Bu, programın aşağıdaki baskısına dönüşür:
Sırada ne var?
Bir sonraki makalemde Covary Dönüşü türünü tanıtacağım. Üye işlevinin Covary iadesi türü, daha yüksek seviyeli bir üye fonksiyonunun daha dar bir tür döndürmesine izin verir. Bu, özellikle prototip tasarım modeli uygulanması gerekiyorsa yararlıdır.
(harita)
Ne yazık ki, bu bağlantı artık geçerli değil.
Boşa harcanan eşyalara olan bağlantılar, 7 günlük daha büyükse veya çok sık çağrılmışsa gerçekleşmez.
Bu makaleyi okumak için bir Haberler+ paketine ihtiyacınız var. Şimdi yükümlülük olmadan bir hafta deneyin – yükümlülük olmadan!
Yazılımın geliştirilmesinde salak: Yineleyici protokolü
Bir tür kişiselleştirilmiş mira verisi aralık tabanlı bir döngüde kullanılması gerekiyorsa, MyType yineleyici protokolünü uygulamalıdır.

Bir döngüde aralığa dayalı olarak kullanılabilmesi için kişiselleştirilmiş bir veri türü nasıl elde edilmelidir? Bu sorunun dibine gidiyorum.
Döngü tabanlı bir aralık için gereksinimler
Basit bir deneyle başlamak istiyorum ve std::array C ++ 'da içgörü 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;
}
C ++ Insights aşağıdaki kodu oluşturur:
#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 olarak formüle edildi: Aralık tabanlı bir döngü kullanılmalıdır (for(range_declaration : range_expression)), derleyici aşağıdaki kodu oluşturur:
{
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
- BT terapisi nesnesi:
- operator++: Yineleyiciyi artırır
- operator*: HE tedavisinin dereflenmesi ve mevcut öğeye erişim
- operator!=: Yineleyiciyi başka bir yineleyiciyle karşılaştırın
Şimdi teoriyi çeviriyorum ve bir sayı jeneratörü 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 Üye işlevleri var begin VE end (Satır 1 ve 2), yineleme nesnelerini şöyle döndür begin_ VE end_ başlatılırlar. begin_ VE end_ Kendinizi üretilen sayılar alanına koyun. Bana iç sınıfı bırak Iterator Oluşturulan sayıları kontrol ettiğini analiz edin.
- operator* Geçerli değeri döndürür
- operator++ Mevcut değeri artırır
- operator!= Geçerli değeri end_-Marka.

Yineleyiciyi istiyorum begin() VE end() İade edilir, genelleştirilir ve onu bir yayıncı ileriye götürür. Yani sınıf yapabilir Generator Standart model kitaplığın çoğu algoritmalarında. Örneğin, ilişkisel kaplar ileri bir düzenleyiciyi destekler.
İleri bir yayıncı
Aşağıdaki gelişti Generator bir iç sınıfı var IteratorBu ileri bir yayıncı.
// 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:
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 İhtiyaçlar Iterator Üyenin işlevlerinin aşağıdaki beyanlarında kullandığım bazı aliase. Programdaki yineleyicinin önceki uygulamasına ek olarak iterator.cpp Mevcut yineleyici, üyenin aşağıdaki işlevlerini destekler: PFEIL operatörü (operator-> 2. satırda), açma sonrası operatör (operator++(int) 3. satırda) ve eşitlik operatörü (operator== 4. satırda).
Şimdi geliştirilmiş jeneratör aralık tabanlı bir döngüde (satır 5), aynı zamanda STL algoritmasında da kullanılabilir std::accumulate. Satır 6'daki kod, 1'den 10'a kadar tüm sayıların toplamını hesaplar; Benzer bir görev satır 7'de izlenir: 1 ila 11 arasında bir sayı burada çarpılır. İlk durumda, toplam için nötr eleman 0'ı seçiyorum, ikinci durumda çarpma için nötr element 1.
Birinci ve ikinci çağrı arasında güzel bir fark var 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ı, üyenin işlevlerini doğrudan kullanır begin() VE end() uyguladığım jeneratörün.
Bu, programın aşağıdaki baskısına dönüşür:

Sırada ne var?
Bir sonraki makalemde Covary Dönüşü türünü tanıtacağım. Üye işlevinin Covary iadesi türü, daha yüksek seviyeli bir üye fonksiyonunun daha dar bir tür döndürmesine izin verir. Bu, özellikle prototip tasarım modeli uygulanması gerekiyorsa yararlıdır.
(harita)
Ne yazık ki, bu bağlantı artık geçerli değil.
Boşa harcanan eşyalara olan bağlantılar, 7 günlük daha büyükse veya çok sık çağrılmışsa gerçekleşmez.
Bu makaleyi okumak için bir Haberler+ paketine ihtiyacınız var. Şimdi yükümlülük olmadan bir hafta deneyin – yükümlülük olmadan!