
C++23: Çok Boyutlu Bir Görünüm
Bir std::mdspan, bağlantılı bir nesne dizisinin tescilli olmayan, çok boyutlu bir görünümüdür. Basit bir C dizisi, bir boyutlu bir işaretçi olabilir std::array
A std::vector
ah std::string
davranmak.
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.
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. std::mdspan's
Boyut, 0 olmayan tüm boyutların çarpımıdır. std::mdspan
çok boyutlu indeks operatörü ile []
erişim.
Her boyut bir std::mdspan
yapabilirsiniz statik uzantı veya bir dinamik uzantı Sahip olmak. statik uzantı bu, uzunluklarının derleme zamanında belirlendiği anlamına gelir; dinamik uzantı uzunluklarının çalışma zamanında sabit olduğu anlamına gelir.
İşte birinin tanımı std::mdspan
:
template<
class T,
class Extents,
class LayoutPolicy = std::layout_right,
class AccessorPolicy = std::default_accessor<T>
> class mdspan;
T
: nesnelerin birbirine bağlı dizisi,Extents
: boyut olarak boyutların sayısını belirtir; her boyutta bir tane olabilir statik uzantı veya bir dinamik uzantı Sahip olmak.LayoutPolicy
: Temel depolamaya erişim için düzen ilkesini ayarlayın.AccessorPolicy:
temel öğelere nasıl başvurulacağını belirler.
C++17’deki sınıf şablonu argüman kesintisi (CTAG) sayesinde, derleyici genellikle şablon argümanlarını başlatıcı 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. (1)’de bir için olur std::vector
(2) ve (3)’te kullanılmış ve std::mdspan
. İlk iki boyutlu dizi m
(2, 4) formuna sahiptir, ikincisi m2
(4, 2) formuna sahiptir. (4) ve (5)’te ikisinin sıraları vardır. std::mdspan
görüntülenir. Her boyutun (6 ve 7) genişletilmesi ve (8)’deki indeks operatörü sayesinde, çok boyutlu diziler arasında yineleme yapmak oldukça basittir.
Çok boyutlu bir dizi ise statik uzantı sahip olmanız gerekiyorsa, şablon argümanlarını belirtmeniz gerekir.
// staticDynamicExtent.cpp
#include <mdspan>
#include <iostream>
#include <string>
#include <vector>
#include <tuple>
int main() {
std::vector myVec{1, 2, 3, 4, 5, 6, 7, 8};
std::mdspan<int, std::extents<std::size_t, 2, 4>>
m{myVec.data()}; // (1)
std::cout << "m.rank(): " << m.rank() << 'n';
for (std::size_t i = 0; i < m.extent(0); ++i) {
for (std::size_t j = 0; j < m.extent(1); ++j) {
std::cout << m[i, j] << ' ';
}
std::cout << 'n';
}
std::cout << 'n';
std::mdspan<int, std::extents<std::size_t, std::dynamic_extent,
std::dynamic_extent>> m2{myVec.data(), 4, 2};// (2)
std::cout << "m2.rank(): " << m2.rank() << 'n';
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';
}
std::cout << 'n';
}
program staticDynamicExtent.cpp
önceki programa göre mdspan.cpp
ve aynı çıktıyı üretir. Aradaki fark şu ki std::mdspan m
(1 bir statik uzantı sahip olmak. Bütünlüğü uğruna: std::mdspan m2
(2) bir tane var dinamik uzantıT. Sonuç olarak, şekli m
model argümanlarının biçimini belirten m2
ancak işlev argümanlarıyla.
düzen stratejisi
A std::mdspan
temel depolamaya erişim için düzen stratejisini belirlemenize olanak tanır. Varsayılan olarak std::layout_right
(C, C++ veya Python stili) ancak siz de yapabilirsiniz std::layout_left
(Fortran veya MATLAB stili). Aşağıdaki resim dosyadaki öğelerin sırasını göstermektedir. std::mdspan
yol açar.
İki kişinin geçişi std::mdspan
düzen stratejileriyle std::layout_right
VE std::layout_left
farkı gösterir.
// mdspanLayout.cpp
#include <mdspan>
#include <iostream>
#include <vector>
int main() {
std::vector myVec{1, 2, 3, 4, 5, 6, 7, 8};
std::mdspan<int, std::extents<std::size_t, // (1)
std::dynamic_extent, std::dynamic_extent>,
std::layout_right> m2{myVec.data(), 4, 2};
std::cout << "m.rank(): " << m.rank() << 'n';
for (std::size_t i = 0; i < m.extent(0); ++i) {
for (std::size_t j = 0; j < m.extent(1); ++j) {
std::cout << m[i, j] << ' ';
}
std::cout << 'n';
}
std::cout << 'n';
std::mdspan<int, std::extents<std::size_t, // (2)
std::dynamic_extent, std::dynamic_extent>,
std::layout_left> m2{myVec.data(), 4, 2};
std::cout << "m2.rank(): " << m2.rank() << 'n';
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';
}
}
THE std::mdspan m
kullanılmış std::layout_right
(1), diğeri std::mdspan std::layout_left
(2). Sınıf şablonu argümanlarını çıkararak, yapıcı çağrıları std::mdspan
(2) açık bir kalıp argümanı yoktur ve ifadeye eşdeğerdir std::mdspan m2{myVec.data(), 4, 2}
.
Program çıktısı iki farklı yerleşim stratejisini gösterir:
Aşağıdaki tabloda arayüze genel bir bakış sunulmaktadır std::mdspan md.
Sıradaki ne?
C++20 belirli eşyordamlar sunmaz ancak bunların uygulanması için bir çerçeve sağlar. Bu C++23 ile değişir. std::generator
ilk somut koroutindir.
(kendim)