C++26'ya genel bakış: Kitaplıkta aritmetik genişletme

Adanali

Active member
C++26'ya genel bakış: Kitaplıkta aritmetik genişletme


  1. C++26'ya genel bakış: Kitaplıkta aritmetik genişletme

C++26 kütüphanesinin yeni özelliklerine genel bir bakış yaptıktan sonra şimdi ikinci yazımda aritmetik açılımı kısaca tanıtacağım.


Duyuru














Rainer Grimm uzun yıllardır yazılım mimarı, ekip ve eğitim yöneticisi olarak çalışmaktadır. C++, Python ve Haskell programlama dilleri üzerine makaleler yazmaktan hoşlanıyor, aynı zamanda özel konferanslarda sık sık konuşmaktan da hoşlanıyor. Modern C++ adlı blogunda C++ tutkusunu yoğun bir şekilde ele alıyor.







std::submdspan


C++26'daki yenilik alt yayılmadır std::submdspan. Mevcut açıklığın bir alt açıklığıdır std::mdspan (C++23), C++23'ün kendisinde yer almıyordu.

C++26'ya geçmeden önce C++23'e kısa bir yoldan gitmem gerekiyor.

std::mdspan


A std::mdspan bağlantılı bir nesne dizisinin tescilli olmayan, çok boyutlu bir görünümüdür. Nesnelerin bitişik dizisi basit bir C dizisi, bir boyut işaretçisi, bir std::array ah std::string Olmak. Bu çok boyutlu görünüme genellikle çok boyutlu dizi adı verilir.

Boyutların sayısı ve her boyutun boyutu, çok boyutlu dizinin şeklini belirler. Boyut sayısına rütbe, her boyutun boyutuna ise kapsam adı verilir. boyutu std::mdspan BENst, 0 olmayan tüm boyutların çarpımıdır. Birinin elemanları üzerinde std::mdspan çok boyutlu indeks operatörü ile yapabilirsiniz [] giriş yapabilirsiniz.

Her boyut bir std::mdspan yapabilirsiniz statik VEYA dinamik uzantı Sahip olmak. statik uzantı bu, uzunluklarının derleme zamanında belirtildiği anlamına gelir; dinamik uzantı uzunluğunun çalışma zamanında belirtildiği anlamına gelir.

C++17'deki Sınıf Şablonu Bağımsız Değişken Türetme (CTAG) sayesinde, derleyici genellikle şablon bağımsız değişkenlerini başlatma veri türlerinden otomatik olarak türetebilir:


// mdspan.cpp

#include <mdspan>
#include <iostream>
#include <vector>

int main() {

std::vector myVec{1, 2, 3, 4, 5, 6, 7, 8}; // (1)

std::mdspan m{myVec.data(), 2, 4}; // (2)
std::cout << "m.rank(): " << m.rank() << 'n'; // (4)

for (std::size_t i = 0; i < m.extent(0); ++i) { // (6)
for (std::size_t j = 0; j < m.extent(1); ++j) { // (7)
std::cout << m[i, j] << ' '; // (8)
}
std::cout << 'n';
}

std::cout << 'n';

std::mdspan m2{myVec.data(), 4, 2}; // (3)
std::cout << "m2.rank(): " << m2.rank() << 'n'; // (5)

for (std::size_t i = 0; i < m2.extent(0); ++i) {
for (std::size_t j = 0; j < m2.extent(1); ++j) {
std::cout << m2[i, j] << ' ';
}
std::cout << 'n';
}

}


Bu örnekte sınıf modeli argüman çıkarımını üç kez uyguluyorum. Satırda (1) bir kişi için kullanılır std::vector (2) ve (3) numaralı satırlarda bir için kullanılır std::mdspan. İlk iki boyutlu dizi m (2, 4) formuna sahiptir, ikincisi m2 (4, 2) formu. (4) ve (5) numaralı satırlarda her ikisinin de sıraları std::mdspan görüntülenir. Her boyutun genişletilmesi (satır 6 ve 7) ve satır (8)'deki indeks operatörü sayesinde, çok boyutlu diziler arasında yineleme yapmak kolaydır.

C++23 gezim burada bitiyor ve C++26'ya geçiyorum std::submdspan sürekli.

std::submdspan


fonksiyon std::submdspan başlangıçta genel işlevsellik açısından çok önemli olduğu düşünülüyordu. mdspan görüntülenir. Ancak inceleme sırasında zaman kısıtlaması nedeniyle başlangıçta tekrar kaldırıldı mdspan C++23'e dahil edilebilir.

Bir tane oluşturmak std::submdspan çok basit. İlk parametre bir mdspan xve geri kalanı x.rank()-Parametreler, her boyut için bir tane olmak üzere bölüm tanımlayıcılarıdır. x. Bölüm tanımlayıcıları hangi aralık öğelerinin olduğunu açıklar [0,x.extent(d)) Teil des mehrdimensionalen Indexraums des zurückgegebenen mdspan sind.

Dies führt zu der folgenden grundlegenden Signatur:


template<class T, class E, class L, class A,
class ... SliceArgs)
auto submdspan(mdspan<T,E,L,A> x, SliceArgs ... args);


Dabei muss E.rank() gleich sizeof...(SliceArgs) sein.

Das Proposal P2630R4 enthält neben der Definition eines std::submdspan auch einige Beispiele für ein mdspan mit Rang 1.


int* ptr = ...;
int N = ...;
mdspan a(ptr, N);

// subspan of a single element
auto a_sub1 = submdspan(a, 1);
static_assert(decltype(a_sub1)::rank() == 0);
assert(&a_sub1() == &a(1));

// subrange
auto a_sub2 = submdspan(a, tuple{1, 4});
static_assert(decltype(a_sub2)::rank() == 1);
assert(&a_sub2(0) == &a(1));
assert(a_sub2.extent(0) == 3);

// subrange with stride
auto a_sub3 = submdspan(a, strided_slice{1, 7, 2});
static_assert(decltype(a_sub3)::rank() == 1);
assert(&a_sub3(0) == &a(1));
assert(&a_sub3(3) == &a(7));
assert(a_sub3.extent(0) == 4);

// full range
auto a_sub4 = submdspan(a, full_extent);
static_assert(decltype(a_sub4)::rank() == 1);
assert(a_sub4(0) == a(0));
assert(a_sub4.extent(0) == a.extent(0));


Die gleichen Regeln gelten für den mehrdimensionalen Anwendungsfall:


int* ptr = ...;
int N0 = ..., N1 = ..., N2 = ..., N3 = ..., N4 = ...;
mdspan a(ptr, N0, N1, N2, N3, N4);

auto a_sub = submdspan(a,full_extent_t(), 3, strided_slice{2,N2-5, 2}, 4, tuple{3, N5-5});

// two integral specifiers so the rank is reduced by 2
static_assert(decltype(a_sub) == 3);
// 1st dimension is taking the whole extent
assert(a_sub.extent(0) == a.extent(0));
// the new 2nd dimension corresponds to the old 3rd dimension
assert(a_sub.extent(1) == (a.extent(2) - 5)/2);
assert(a_sub.stride(1) == a.stride(2)*2);
// the new 3rd dimension corresponds to the old 5th dimension
assert(a_sub.extent(2) == a.extent(4)-8);

assert(&a_sub(1,5,7) == &a(1, 3, 2+5*2, 4, 3+7));


Dies ist allerdings noch nicht das Ende der Unterstützung für C++26.

<linalg> – lineare Algebra


linalg ist eine auf BLAS (Basic Linear Algebra Subprograms) basierende, freie Schnittstelle für lineare Algebra. BLAS ist laut Wikipedia eine Spezifikation, die eine Reihe von Low-Level-Routinen zur Durchführung gängiger linearer Algebra-Operationen wie Vektoraddition, skalare Multiplikation, Punktprodukte, Linearkombinationen und Matrixmultiplikation vorschreibt. Sie sind de facto der Standard für Low-Level-Routinen in Bibliotheken der linearen Algebra.

Das Proposal P1673R13 schlägt eine Schnittstelle für die Dense Linear Algebra der C++-Standardbibliothek vor, die auf den Dense Basic Linear Algebra Subroutines (BLAS) basiert. Dies entspricht einer Teilmenge des BLAS-Standards.

Diese lineare Algebra wurde in der C++-Community lange vermisst. Gemäß dem Proposal ist der folgende Codeausschnitt das “Hallo Welt” der linearen Algebra. Er skaliert die Elemente eines 1-D-mdspan um einen konstanten Faktor, zuerst sequenziell, dann parallel:


constexpr size_t N = 40;
std::vector<double> x_vec(N);

mdspan x(x_vec.data(), N);
for(size_t i = 0; i < N; ++i) {
x = çift(ler); } linalg::scale(2.0, x); // x = 2,0 * x linalg::scale(std::execution::par_unseq, 3.0, x); for(size_t i = 0; i < N; ++i) { iddia(x) == 6,0 * çift(ler)); }


Bir sonraki adım nedir?


C++26'daki yenilikler henüz bitmedi. Bir sonraki yazımda C++26'da doygunluk aritmetiği ve eşzamanlılık desteği hakkında yazacağım.


(harita)
 
Üst