Yazılım geliştirme: C++20 biçimlendirme kitaplığı

Peter Gottschling, C++20’deki biçimlendirme kitaplığı üzerine iki mükemmel blog makalesi yazmasına rağmen (“C++20’de std::format”, “C++20: kullanıcı tarafından tanımlanan veri türleriyle std::format’ın genişletilmesi”) , biçimlendirme kütüphanesini yazarak tekrar bakacağım. Nedeni basit: Peter’ın makalesi harika bir giriş ve genel bakış sağlıyordu. Herkesin bu ve bundan sonraki birkaç makaleyi referans olarak kullanabilmesi için tüm detayları sunmak istiyorum.

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.

C++20 aşağıdaki biçimlendirme özelliklerini destekler:

Fonksiyonlar std::format VE std::format_to işlevsel olarak benzerlerine eşdeğerdirler std::vformat VE std::vformat_toancak bazı açılardan farklılık gösterirler:

  • std::format, std::_format_to VE std::format_to_n: Derleme zamanında biçim dizesi olarak bir değere ihtiyaç vardır. Bu biçim dizesi bir olabilir constexpr-String veya bir string değişmezi.
  • std::vformat VE std::vformat_t: Biçim dizesi bir lValue olabilir. Bağımsız değişkenler değişken işleve gitmelidir std::make_format_args üstesinden gelinebilir, örneğin: std::vformat(formatString, std::make_format_args(args)).

Biçimlendirme işlevleri herhangi bir sayıda bağımsız değişken alır. Aşağıdaki program işlevler hakkında ilk izlenimi vermektedir. std::format, std::format_to VE std::format_to_n.

// format.cpp

#include <format>
#include <iostream>
#include <iterator>
#include <string>
 
int main() {
    
    std::cout << 'n';

    std::cout << std::format("Hello, C++{}!n", "20") 
      << 'n';                                         // (1)

    std::string buffer;
 
    std::format_to(                                    // (2)
        std::back_inserter(buffer), 
        "Hello, C++{}!n",          
        "20");    
        
    std::cout << buffer << 'n';

    buffer.clear(); 

    std::format_to_n(                                  // (3)
        std::back_inserter(buffer), 5, 
        "Hello, C++{}!n",          
        "20");    
        
    std::cout << buffer << 'n';

    
    std::cout << 'n';
   
}

Program doğrudan (1)’de biçimlendirilmiş karakter dizisini görüntüler. Ancak (2) ve (3)’teki çağrılar arabellek olarak bir dize kullanır. Aynı zamanda itiyor std::format_to_n arabellekte yalnızca beş karakter.

İşte ilgili program std::vformat VE std::vformat_n kullanılmış:

// formatRuntime.cpp

#include <format>
#include <iostream>
#include <iterator>
#include <string>
 
int main() {
    
    std::cout << 'n';

    std::string formatString = "Hello, C++{}!n";

    std::cout << std::vformat(formatString, 
                              std::make_format_args("20"))
              << 'n';                                     // (1)

    std::string buffer;
 
    std::vformat_to(                                       // (2)
        std::back_inserter(buffer), 
        formatString,          
        std::make_format_args("20"));    
        
    std::cout << buffer << 'n';
   
}

THE formatString (1) ve (2)’de bir lValue vardır.

Biçimlendirme işlevlerinin muhtemelen en ilginç kısmı biçim dizesidir ("Hallo, C++{}!n").

Biçim dizesi sözdizimi biçimlendirme işlevlerindedir std::format, std::format_to, std::format_to_n, std::vformat VE std::vformat_to birebir aynı. kullanırım std::format benim örneklerimde

  • Sözdizimi: std::format(FormatString, Argümanlar)

Biçim halkası FormatString oluşur

  • Sıradan karakterler ({ ve } hariç),
  • {{ ve }} kaçış dizileri, ayrıca { ve } ile değiştirildi
  • değiştirme alanları.

Değiştirme alanı { } biçimindedir.

  • Değiştirme alanında bir bağımsız değişken kimliği ve iki nokta üst üste kullanıp ardından bir biçim belirtimi kullanabilirsiniz. Her iki bileşen de isteğe bağlıdır.

Konu kimliği, konu dizinini almak için kullanılabilir Args belirtmek. Kimlikler 0 ile başlar. Konu kimliği belirtilmezse alanlar, konuların belirtildiği sırayla doldurulur. Tüm değiştirme alanlarında konu kimliği kullanılmalı veya hiç kullanılmamalıdır; Bu şu anlama gelir std::format("{}, {}", "Hallo", "Welt") VE std::format("{1}, {0}", "Welt", "Hallo") Her ikisi de derlenmiştir, ancak std::format("{1}, {}", "Welt", "Hallo") Olumsuz.

std::formatter ve uzmanlıkları, argüman türleri için format spesifikasyonunu tanımlar.

  • Temel veri türleri e std::string: Python format spesifikasyonunu temel alırlar.
  • Krono türleri: Sonraki makalelerden birinde bunları tanıtacağım.
  • Diğer biçimlendirilebilir veri türleri: Özel std::formatter-Uzmanlık. Bunları başka bir yazımda tanıtacağım.

Biçim dizelerinin bir derleme zamanı değişkeni olması gerçeğinin iki ilginç sonucu vardır: performans ve güvenlik.

  • Performans: Biçim dizesi derleme zamanında kontrol edilirse çalışma zamanında hiçbir şey yapmanıza gerek yoktur. Buna göre, üç işlev vaat ediyor std::format, std::format_to VE std::format_to_n mükemmel bir performans. Fmt prototip kütüphanesinin bazı ilginç kriterleri vardır.
  • Güvenlik: Derleme zamanında yanlış biçim dizesinin kullanılması derleme hatasına neden olur. Bunun yerine çalışma zamanında bir biçim dizesi kullanmak std::vformat VEYA std::vformat_to bir std::format_error-İstisna.

Bir sonraki blog yazımda teoriyi pratikle bütünleştireceğim.


(kendim)

Haberin Sonu

Bir yanıt yazın

E-posta adresiniz yayınlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir