Yazılım geliştirmede deyimler: düzenli veri türleri

Adanali

Active member
Yazılım geliştirmede deyimler: düzenli veri türleri


  1. Yazılım geliştirmede deyimler: düzenli veri türleri

Normal tür kavramı, Standart Şablon Kitaplığı’nın (STL) babası Alexander Stepanov’a kadar uzanır. Normal tür, yerleşik bir veri türü gibi davranan kullanıcı tanımlı bir veri türüdür.







Rainer Grimm, uzun yıllardır yazılım mimarı, ekip lideri ve eğitim yöneticisi olarak çalışmaktadır. C++, Python ve Haskell programlama dilleri üzerine makaleler yazmaktan hoşlanır, aynı zamanda sık sık uzmanlık konferanslarında konuşmaktan da keyif alır. Modernes C++ blogunda yoğun bir şekilde C++ tutkusundan bahsediyor.













Beton tipi terimi, düzenli tip terimi ile yakından ilgilidir. Bu yüzden bu makaleye somut tip kavramıyla başlamak istiyorum.

beton tipi

  • Açık beton tipi C++ temel yönergelerine uygundur”en basit sınıf türüAyrıca genellikle bir değer türü olarak adlandırılır ve bir tür hiyerarşisinin parçası değildir.
  • Açık normal tip bir veri türüdür “int gibi davranır“ve bu nedenle kopyalamayı ve atamayı, eşitliği ve düzeni desteklemelidir.
İşte C++ Temel Yönergelerinden daha fazla not:

C.10: Sınıf hiyerarşilerine somut türleri tercih edin


Bir sınıf hiyerarşisi için bir kullanım durumunuz olmadığında somut tip tercih edilir. Bir beton tipinin uygulanması çok daha kolay, daha küçük ve daha hızlıdır. Kalıtım, sanallık, referanslar veya işaretçiler veya bellek tahsisi ve serbest bırakma hakkında endişelenmenize gerek yok. Sanal gönderim yoktur ve bu nedenle çalışma zamanı ek yükü yoktur.

Uzun lafın kısası: KISS ilkesi (basit tutun, aptalca) burada geçerlidir. Veri türü bir değer gibi davranır.

C.11: Beton türlerinin düzenli hale getirilmesi

Normal tiplerin (ins) anlaşılması daha kolaydır. Doğuştan sezgiseldirler. Yani, somut bir tipiniz varsa, onu normal bir tipe çevirmelisiniz. Gibi yerleşik veri türleri int veya double düzenliler, ancak kaplar da öyle std::string, std::vector veya std::unordered_map.

Şimdi normal tipler hakkında daha fazla ayrıntıya gireceğim.

normal çocuk


Düzenli tip kavramı, STL’nin babası Alexander Stepanov’a kadar uzanır. Normal tipler hakkındaki fikirlerini “Fundamentals of Generic Programming” adlı makalesinde anlattı ve “Elements of Programming” adlı kitabında bunları geliştirdi.

Düzenli bir veri türünden nasıl yararlanılır? Alexander Stepanov, “Programlamanın Öğeleri” adlı kitabında bunun cevabını veriyor: Bir türün hesaplama temeline dahil edilmesi, nesneleri veri yapılarına yerleştirmemize ve nesneleri bir veri yapısından diğerine kopyalamak için algoritmalar kullanmamıza izin veren bir dizi prosedür vardır. Bu temele sahip türleri düzenli olarak adlandırırız, çünkü kullanımları davranış düzenliliğini ve dolayısıyla birlikte çalışabilirliği garanti eder.

Kısacası, normal tipler sezgisel olarak veri yapılarında ve algoritmalarda yerleşik tipler gibi davranır.

Normal bir veri türü nasıl sezgisel olabilir? “Fundamentals of Generic Programming” belgesine göre, düzenli bir veri türü aşağıdaki işlemleri desteklemelidir:








Bu tablonun işlemleri tanıdık gelmelidir. C++20 konseptine sahiptir std::regular.

Kavram std::regular


Kavram std::regular Stepanov’un normal veri türü fikrine çok benziyor. Esasen hareketin anlamını içerir.

C++20’de normal türler kavramı iki kavram halinde rafine edilmiştir: std::semiregular Ve std::regular.

Yarı düzenli bir veri türü X altı kuralını desteklemeli (“C++ Programlama Dili: Sıfırın Kuralı veya / altı” adlı son makaleme bakın) ve değiştirilebilir olmalıdır.

Yarı-düzenli bir X veri türü, altı kuralını desteklemeli (“Sıfır/Altı Kuralı” başlıklı son makaleme bakın) ve değiştirilebilir olmalıdır:

  • Varsayılan yapıcı: X()
  • Kopya Oluşturucu: X(const X&)
  • Ödevi kopyala: X& operator = (const X&)
  • Oluşturucuyu Taşı: X(X&&)
  • Ödevi Taşı: X& operator = (X&&)
  • yok edici: ~X()
  • değiştirilebilir: swap(X&, X&)
Geriye yalnızca bir özellik kalır ve yarı-düzenli bir X veri türü düzenli hale gelir.

Düzenli bir veri türü T düzenlidir ve eşitlikle karşılaştırılabilir:

  • eşitlik operatörü: operator == (const X&, const X&)
  • eşitsizlik operatörü: operator != (const X&, const X&)
Kavram std::regular C++20’de üç kavram temelinde std::movable, std::copyable Ve std::semiregular.


template<class T>
concept movable = is_object_v<T> && move_constructible<T> &&
assignable_from<T&, T> && swappable<T>;

template<class T>
concept copyable = copy_constructible<T> && movable<T>
&& assignable_from<T&, const T&>;

template<class T>
concept semiregular = copyable<T> && default_constructible<T>;

template<class T>
concept regular = semiregular<T> && equality_comparable<T>;


Kavram std::movable std::is_object türündeki özellik işlevine dayalıdır. İşte cppreference.com’dan olası bir uygulama.


template< class T>
struct is_object : std::integral_constant<bool,
std::is_scalar<T>::value ||
std::is_array<T>::value ||
std::is_union<T>::value ||
std::is_class<T>::value> {};


Ayrıca, konsepte dayalı std::movable kavramlar üzerine std::move_constructible Ve std::assignable_from. Diğer tüm Kavramlar bileşenleri std::copyable Ve std::semiregular bunlar aynı zamanda C++20 kavramlarıdır.

Kavramlar hakkında daha fazla bilgiyi önceki makalelerimde bulabilirsiniz: Kavramlar:

Hangi veri türü düzenli değil? En önemlisi muhtemelen bir referanstır.

Referanslar


Başvuru bir nesne değildir ve ne düzenli ne de yarı düzenlidir:


// referenceIsObject.cpp

#include <funktional>
#include <iostream>
#include <type_traits>

int main() {

std::cout << 'n';

std::cout << std::boolalpha;
std::cout << "std::is_object<int&>::value: "
<< std::is_object<int&>::value << 'n'; // (1)
// 2:
std::cout
<< "std::is_object<std::reference_wrapper<int>>::value: "
<< std::is_object<std::reference_wrapper<int>>::value
<< 'n';

std::cout << 'n';

}



Programın çıktısı bunu açıkça özetliyor. Referans (satır 1) bir nesne değildir:








Programda 2. satırın üstünde kim var? referenceIsObject.cpp harikalar: bir referans int& bu bir nesne değil, ancak bir referans sarmalayıcı std::reference_wrapper<int> bir obje. İşte cppreference.com adresindeki bir referans paketleyicinin açıklaması: std::reference_wrapper, bir referansı kopyalanabilir ve atanabilir bir nesneye saran bir sınıf şablonudur. Genellikle referansları normalde referans içeremeyen standart kaplar (std::vector gibi) içinde depolamak için bir mekanizma olarak kullanılır.

Bu, bir referans vektörü anlamına gelir std::vector<int&> bir referans sarma vektörünün aksine std::vector<std::reference_wrapper<int>> geçerli değil. Bu nedenle, C++ 11’den bu yana referans semantiği olan bir kapsayıcı uygulamak mümkündür.


// referenceSemantics.cpp

#include <functional>
#include <iostream>
#include <list>
#include <type_traits>
#include <vector>

int main() {

std::cout << 'n';

std::list<int> myList{1, 2, 3, 4, 5};
std::vector<std::reference_wrapper<int>>
myRefVector(myList.begin(), myList.end());

for (auto l: myList) std::cout << l << " ";
std::cout << "nn";

for (auto& v: myRefVector) v *= v; // (1)

for (auto l: myList) std::cout << l << " "; // (2)

std::cout << "nn";

}


a öğesinin öğelerini değiştirin std::vector<std::reference_wrapper<int>> (1) ayrıca referans elemanlarını (2) değiştirir.








Düzenli bir veri türü alan ancak bir referans kullanan bir algoritmanız varsa C++20’ye ne dersiniz?


// needRegularType.cpp

#include <concepts>

template <std::regular T>
class MyClass{};

int main() {

MyClass<int> myClass1;
MyClass<int&> myClass2;

}


Programı güncel GCC 12.2, güncel clang 15.0.0 ve güncel msvc v19 derleyici ile derledim. Microsoft derleyicisi en iyi hata mesajını verdi:








Sıradaki ne?


Value nesnesi, eşitliği kimliğine değil durumuna bağlı olan küçük bir nesnedir. Değerli eşyalar bir sonraki yazımın konusu olacak.


(rm)



Haberin Sonu
 
Üst