C ++ 23: Bunun kesintisi ile sözdizimsel şeker

Adanali

Active member
C ++ 23: Bunun kesintisi ile sözdizimsel şeker


  1. C ++ 23: Bunun kesintisi ile sözdizimsel şeker

. Cçirkin Rıvır zıvır TEmpiate modelleri (CRTP) C ++ 'da sık kullanılan bir dildir. En son makalemde nasıl sunduğum klasik tasarım modeli Vicher'in “C ++ 23: Açık Bölümlerin Bu Oluşturulmasını Düşür”. Bunun kesintisi sayesinde C ve R'yi kısaltmadan kaldırabiliriz.










Rainer Grimm yıllardır yazılım mimarı, ekip ve eğitim müdürü olarak çalıştı. C ++ programlama dilleri, Python ve Haskell hakkında makaleler yazmayı seviyor, ancak uzman konferanslarla konuşmayı da seviyor. Modern C ++ blogunda, C ++ tutkusuyla yoğun bir şekilde ilgileniyor.













CTP


CTP kısaltması C ++ dilini ifade ediyor Cçirkin Rıvır zıvır Tfakir PÖzenli ve C ++ 'da bir sınıfta bir tekniği gösterir Derived Bir sınıf modeli ile Base Türetilmiştir. En önemli nokta şu ki Base Derived Model bir konusu var.



template <typename T>
class Base{
...
};

class Derived : public Base<Derived>{
...
};


CTP genellikle statik polimorfi uygulamak için kullanılır. Dinamik polimorfinin aksine, bu derleme döneminde meydana gelir ve herhangi bir pahalı Dolaylı işaretçi.

C ++ 98



Aşağıdaki program crtp.cpp C ++ 98'de CTP tabanlı bir deyimsel uygulama sunun.



// crtp.cpp

#include <iostream>

template <typename Derived>
struct Base{
void interface(){ // (2)
static_cast<Derived*>(this)->implementation();
}
void implementation(){ // (3)
std::cout << "Implementation Base" << 'n';
}
};

struct Derived1: Base<Derived1>{
void implementation(){
std::cout << "Implementation Derived1" << 'n';
}
};

struct Derived2: Base<Derived2>{
void implementation(){
std::cout << "Implementation Derived2" << 'n';
}
};

struct Derived3: Base<Derived3>{}; // (4)

template <typename T> // (1)
void execute(T& base){
base.interface();
}

int main(){

std::cout << 'n';

Derived1 d1;
execute(d1);

Derived2 d2;
execute(d2);

Derived3 d3;
execute(d3);

std::cout << 'n';

}


Fonksiyonel model execute (1) Statik polimorfinin kullanımı. Üye işlevi Base::interface (2) CTP dilinin anahtarıdır. Üye işlevi, çağrıyı türetilmiş sınıfın uygulanmasına yönlendirir: static_cast<Derived*>(this)->implementation. Bu mümkündür çünkü işlev sadece çağrıldığında başlatılır. O zamanlar onlar türev sınıflar Derived1,, Derived2 VE Derived3 tamamen tanımlanmış. Bu nedenle işlev olabilir Base::interface Türev sınıflarının uygulanmasını kullanın. Üyenin işlevi ilginç Base::implementation (3). Sınıf -statik polimorfi için varsayılan uygulama rolüne sahiptir Derived3 (4). Aşağıdaki şekilde statik polimorfiyi çalışırken göstermektedir.









C ++ 23

Açık nesne parametresi sayesinde C ve R, CTP kısaltmasından kaldırılabilir.









Program deducingThisCRTP.cpp Uygulamayı C ++ 23'e göre koyun BükülmeDaha önce TP.



// deducingThisCRTP.cpp

#include <iostream>

struct Base{ // (1)
template <typename Self>
void interface(this Self&& self){
self.implementation();
}
void implementation(){
std::cout << "Implementation Base" << 'n';
}
};

struct Derived1: Base{
void implementation(){
std::cout << "Implementation Derived1" << 'n';
}
};

struct Derived2: Base{
void implementation(){
std::cout << "Implementation Derived2" << 'n';
}
};

struct Derived3: Base{};

template <typename T>
void execute(T& base){
base.interface(); // (2)
}

int main(){

std::cout << 'n';

Derived1 d1; // (3)
execute(d1);

Derived2 d2; // (4)
execute(d2);

Derived3 d3; // (5)
execute(d3);

std::cout << 'n';

}


Açık nesnenin parametreleri, türev türünü türetmenize ve mükemmel bir şekilde iletmenize izin verir (1). (2) 'de belirli bir tür için Derived1 (3), Derived2 (4) e Derived3 (5) kullanıldı. Sonuç olarak, muhabir sanal işlev implementation İsminde: std::forward<Self>(self).implementation(). Program zaten geçerli Microsoft derleyicisi ile gerçekleştirilebilir.









Lambdas özyinelemeli


Son Alman katkım hakkında bunu çıkarmak için en canlı uygulamaları unuttuğum hakkında bir yorum aldım: Lambdas özyinelemeli. Dürüst olmak gerekirse, bunun bunun kesintisinin en iyi kullanımı olduğundan emin değilim, çünkü çoğu programcının özyineleme ile ilgili sorunları var. İkincisi, ben karmaşık bir Lambdas hayranı değilim. Lambdas özlü ve araba doktoru olmalıdır.

Şimdi yinelemeli bir şekilde tanımlanan fakülte fonksiyonunun çeşitli uygulamalarını sunuyorum. Daha sonra, herkes hangi sürümün okunması daha kolay olduğuna kendi başlarına karar verebilir.

Her işlev 10: 3628800 fakültesini hesaplar.

C ++ 98

C ++ 98'de iki seçeneğiniz var: özyinelemeli bir istek veya fonksiyonel bir çağrı ile ölçüm önlemleri programlamasını kullanın. Memplate hedefi derleme zamanı için gerçekleştirilir.



// factorial_cpp98.cpp

#include <iostream>

template <unsigned int N>
struct Factorial{
static int const value = N * Factorial<N-1>::value;
};



template <>
struct Factorial<0>{
static int const value = 1;
};

int factorial(unsigned int n){
return n > 0 ? n * factorial(n - 1): 1;
}

int main(){

std::cout << 'n';

std::cout << "Factorial<10>::value: "
<< Factorial<10>::value << 'n';
std::cout << "factorial(10) "
<< factorial(10) << 'n';

std::cout << 'n';

}


Modelin metaproogramı durumunda, 2 ila 10 değeri için eksiksiz bir model oluşturulur: https://cppinsights.io/s/b7a2cbd6.

C ++ 11

C ++ 11'de faktöriyel işlev olabilir constexpr Derleme için gerçekleştirilme potansiyeline sahiptir.



// factorial_cpp11.cpp

#include <iostream>

constexpr int factorial(unsigned int n){
return n > 0 ? n * factorial(n - 1): 1;
}

int main(){

std::cout << 'n';

std::cout << "factorial(10) " << factorial(10) << 'n';

std::cout << 'n';

}


C ++ 17

Sayesinde constexp if Farklı koda bağlı olarak, N > 0 ya da değil. C ++ 11'deki Memplate Meta programına gelince, derleyici 2'den 10'a kadar olan değerler için tamamen özel modeller üretir: https://cppinsights.io/s/650b62f0.



// factorial_cpp17.cpp

#include <iostream>

template <unsigned int N>
constexpr int factorial() {
if constexpr (N > 0)
return N * factorial<N - 1>();
else
return 1;
}

int main(){

std::cout << 'n';

std::cout << "factorial<10>() " << factorial<10>() << 'n';

std::cout << 'n';

}


A constexpr-Kunksiyon (C ++ 11) derleme zamanına sahiptir, ancak bir consteval-Konka (C ++ 20) derlemesi için yapılmalıdır.

C ++ 20



// factorial_cpp20.cpp

#include <iostream>

consteval int factorial(unsigned int n){
return n > 0 ? n * factorial(n - 1): 1;
}

int main(){

std::cout << 'n';

std::cout << "factorial(10) " << factorial(10) << 'n';

std::cout << 'n';

}


Sonuçta, C ++ 23'te sona erdim. C ++ 23'te bir lambda kendine başvurabilir. Bu, özyinelemeli bir lambda uygulamamı sağlıyor.

C ++ 23



// factorial_cpp23.cpp

#include <iostream>

auto factorial = [](this auto&& self, unsigned int n) -> int {
return n > 0 ? n * self(n - 1): 1;
};

int main(){

std::cout << 'n';

std::cout << "factorial(10) " << factorial(10) << 'n';

std::cout << 'n';

}


MSVC derleyicisi bunu çıkararak bunları tam olarak desteklemez. Bu yüzden iade türünü iade etmeliyim (-> int) özyinelemeli lambda. P0847R7 teklifine göre, bu gerekli değildir.



auto factorial = [](this auto&& self, unsigned int n) {
return n > 0 ? n * self(n - 1): 1;
};


İşte programın baskısı:









Herkes fakülte işlevinin farklı bir varyantını tercih edebilir. Favorim C ++ 20 versiyonu consteval temelli.

Sırada ne var?


Ana dili C ++ 23, bunu çıkarmaktan daha fazla özellik sunar. Bir sonraki makalem tam olarak bu özelliklerle ilgilidir.


(RME)
 
Üst