top of page

C++ Dilinde std::format_to

  • Writer: Yusuf Hançar
    Yusuf Hançar
  • Nov 7, 2024
  • 5 min read

Updated: Nov 7, 2024

template <class OutputIt, class... Args>
OutputIt format_to(OutputIt out, std::format_string<Args...> fmt, Args&&... args);

template <class OutputIt, class... Args>
OutputIt format_to(OutputIt out, std::wformat_string<Args...> fmt, Args&&... args);

template <class OutputIt, class... Args>
OutputIt format_to(OutputIt out, const std::locale& loc,
                   std::format_string<Args...> fmt, Args&&... args);

template <class OutputIt, class... Args>
OutputIt format_to(OutputIt out, const std::locale& loc,
                   std::wformat_string<Args...> fmt, Args&&... args);

Önceki yazımızda std::format kütüphanesini inceledik ve C++20 ile artık kolayca kullanım sunduğunu örneklerle pekiştirdik. Bu yazıda std::format_to inceleyeceğiz.

std::format_to destination olarak bir adres alır ve formatlı yazıyı o adreste oluşturur yani oraya insert eder. Parametresine herhangi bir iterator geçilebilir.(ostream_iterator, ostream_buf_iterator, insert_iterator ...) std::format gibi string döndürmez verilen iteator konumdan başlayarak yazar. geri dönüş değeri de son yazdığı yerin konumudur. format string fmt parametresine göre argümanları biçimlendirir ve sonucu output iterator'e yazar, mevcutsa loc, locale-specific formatting için kullanılır.


#include <iostream>
#include <format>
#include <string>
#include <iterator>

int main()
{
    int x{ 12'254'478 };

    std::format_to(std::ostream_iterator<char>(std::cout), "|{:^#16X}|", x);
} 
*****************************      
AÇIKLAMA : 
*****************************     
CEVAP : |    0XBAFD0E    |
*****************************

int main()
{
    std::string str;
    int x{ 20 };

    std::format_to(back_inserter(str), "|{:^#16X}|", x);

    std::cout << "len : " << str.length() << "\n";
    std::cout << "str : " << str << "\n";
}  
*****************************      
AÇIKLAMA : 
*****************************     
CEVAP :
len : 18
str : |      0X14      |
*****************************

int main()
{
    std::string name{ "std::format_to - cpp20" };
    int id{ 78945 };
    double dval{ 54.456789 };
    std::string str;

    std::format_to(back_inserter(str), "|{} {} {:2f}|", id, name, dval);

    std::cout << str << '\n';
} 
*****************************      
AÇIKLAMA : 
*****************************     
CEVAP : |78945 std::format_to - cpp20 54.456789|
*****************************

int main()
{
    std::string name{ "02ppc" };
    int id{ 78945 };
    double dval{ 54.213455 };
    std::string str;

    std::list<char> clist;

    std::format_to(front_inserter(clist), "|{} {} {:2f}|", id, name, dval);

    for (auto c : clist)
    {
        std::cout << c;
    }
} 
*****************************      
AÇIKLAMA : 
*****************************     
CEVAP : |554312.45 cpp20 54987|
*****************************

int main()
{
    std::string str;

    for (char c = 'A'; c <= 'Z'; ++c)
    {
        std::format_to(back_inserter(str), "|{{{0}, {0:d}}}|", c);
    }

    std::cout << str << "\n";
}  
*****************************      
AÇIKLAMA : 
*****************************     
CEVAP :
|{A, 65}||{B, 66}||{C, 67}||{D, 68}||{E, 69}||{F, 70}||{G, 71}||{H, 72}||{I, 73}||{J, 74}||{K, 75}||{L, 76}||{M, 77}||{N, 78}||{O, 79}||{P, 80}||{Q, 81}||{R, 82}||{S, 83}||{T, 84}||{U, 85}||{V, 86}||{W, 87}||{X, 88}||{Y, 89}||{Z, 90}|
*****************************

localization

#include <locale>

class locale;

int main()
{
    std::cout << 123.96585 << "\n";
    std::cout << std::format("{:.2f}\n", 4.56) << "\n";  
} 
*****************************      
AÇIKLAMA : 
*****************************     
CEVAP :
123.966
4.56
*****************************

int main()
{
    std::cout << std::format(std::locale("Turkish"), "{:L]\n", 4.56) << "\n";  
}  
*****************************      
AÇIKLAMA : virgül ekledi
*****************************     
CEVAP :
4,56
*****************************

formatted_size

int main()
{
    int x{ 435466 };

    auto len = std::formatted_size("{:#x}", x);

    std::cout << "len : " << len << "\n"; 
}  
*****************************      
AÇIKLAMA : yazının uzunluğu 7 olur.
Bu yazıya bir buffer ayarlamak istesek önce formatted_size çağırılıp o kadarlık bir bellek alanın allocate edilebilir.
*****************************     
CEVAP : len : 7
*****************************

std::format_to_n - std::format_to_n_result

  • 1. parametresi konum

  • 2.parametresi tam sayı değeri ister (en fazla o kadar tam sayı yazacak)

  • return değeri yapı türündendir. (format_to_n_result<....> )


int main()
{
    std::string lang{ "cpp" }, str{ "2020-2023" };
    std::array<char, 9> arr{};

    std::format_to_n(arr.data(), arr.size() - 1, "{} {}", lang, str);

    for (char c : arr)
    {
        std::cout << c;
    }

    std::cout << "\n";    
}
*****************************      
AÇIKLAMA : sadece 8 karakter yazıldı.
*****************************     
CEVAP : cpp 2020
*****************************

int main()
{
    std::string lang{ "cpp" }, str{ "2020-2023" };
    std::array<char, 20> arr{};

    auto val = std::format_to_n(arr.data(), arr.size() - 1, "{} {}", lang, str);

    std::cout << "val.size : " << val.size << "\n";  
}  
*****************************      
AÇIKLAMA : 
*****************************     
CEVAP : val.size : 13
*****************************

int main()
{
    std::string lang{ "cpp" }, str{ "2020-2023" };
    std::array<char, 20> arr{};

    auto val = std::format_to_n(arr.data(), arr.size() - 1, "{} {}", lang, str);

    std::cout << "index : " << val.out - arr.data() << "\n";  
}  
*****************************      
AÇIKLAMA : 2 pointer farkı uzunluğudur.
*****************************     
CEVAP : index : 19
*****************************

kendi türümüz içinde formatlama yani std::format ile kullanılması için std::formatter sınıfının kendi türümüz için explicit specialization'ını oluşturmamız gerekir

  • std::format_context

template< class OutputIt, class CharT >
class basic_format_context;

using format_context = basic_format_context</* unspecified */, char>;

using wformat_context = basic_format_context</* unspecified */, wchar_t>;

Member functions

(constructor) [deleted]

basic_format_context cannot be constructed by user code(public)

operator=[deleted]

basic_format_context is not assignable(public)

arg

returns the argument at the given index(public)

locale

returns the locale used for locale-specific formatting(public)

out

returns the iterator to output buffer(public)

advance_to

advances the output iterator to the given position(public)


Member types

Type

Definition

iterator

OutputIt

char_type

CharT


Member alias templates

Type

Definition

formatter_type<T>

std::formatter<T, CharT>

class Software {
public:
    Software(std::string lang, int id) : m_lang(std::move(lang)), m_id(id) {}

    std::string get_language() const 
    { 
        return m_lang; 
    }
    
    int get_id() const 
    { 
        return m_id; 
    }

private:
    std::string m_lang;
    int m_id;
};

template <>
struct std::formatter<Software> {
    enum class LangType { Lang, Id, All };
    
    LangType m_ftype{LangType::All}; 

    // Biçim seçeneklerini ayrıştır
    constexpr auto parse(std::format_parse_context& ctx) 
    {
        auto iter = ctx.begin();
        const auto end = ctx.end();

        if (iter != end) 
        {
            switch (*iter) 
            {
                case 'l': m_ftype = LangType::Lang; break;
                case 'i': m_ftype = LangType::Id; break;
                case 'a': m_ftype = LangType::All; break;
                default: throw std::format_error("Invalid format specifier for Software");
            }
            
            ++iter;
        }

        if (iter != end && *iter != '}')
        {
            throw std::format_error("Invalid format specifier for Software");
        }

        return iter;
    }

    auto format(const Software& p, std::format_context& ctx) const 
    {
        switch (m_ftype) 
        {
            case LangType::Lang: 
                return std::format_to(ctx.out(), "{}", p.get_language());
            case LangType::Id: 
                return std::format_to(ctx.out(), "{}", p.get_id());
            case LangType::All: 
                return std::format_to(ctx.out(), "[{} {}]", p.get_id(), p.get_language());
        }
        
        return ctx.out();
    }
};

int main() 
{
    Software s1{"cpp", 17};
    Software s2{"cpp", 20};
    Software s3{"cpp", 23};

    std::cout << std::format("{:l}\n{:i}\n{:a}\n", s1, s2, s3);
    
    return 0;
}
*****************************      
AÇIKLAMA :
*****************************     
CEVAP :
cpp
20
[23 cpp]
*****************************




class Always40 {
public :
    int get_val() const
    {
        return 40;
    }
};

template<>
struct std::formatter<Always40> {
    // parse the format string for this type:
    constexpr auto parse(std::format_parse_context& ctx)
    {
        return ctx.begin();    // return position of } (hopefully there)
    }

    // format by always writing its value :
    auto format(const Always40& obj, std::format_context& ctx) const 
    {
        return std::format_to(ctx.out(), "{}", obj.get_val());
    }
};

int main ()
{
    std::cout << std::format("|{}|\n", Always40{});
}

int main ()
{
    auto val = Always40{};

    std::cout << std::format("|{0} {0} {0}|\n", val);
}
*****************************      
AÇIKLAMA :
*****************************     
CEVAP : |40 40 40|
*****************************

struct Point {
    int mx, my;
};

template <>
struct std::formatter<Point> {
public:
    constexpr auto parse(std::format_parse_context& pc) 
    {
        auto iter = pc.begin();
        
        while (iter != pc.end() && *iter != '}') 
        {
            if (*iter == '#') 
            {
                m_cb = true;
            } 
            else 
            {
                throw std::format_error("invalid formatting char!");
            }
            
            ++iter;
        }
        
        return iter;
    }

    auto format(const Point& p, std::format_context& fc) const 
    {
        char open_char = m_cb ? '{' : '(';
        char close_char = m_cb ? '}' : ')';
        
        return std::format_to(fc.out(), "{}{}, {}{}", open_char, p.mx, p.my, close_char);
    }

private:
    bool m_cb = false;
};

int main() 
{
    Point p1{ 2, 6 }, p2{ 3, 5 };

    std::cout << std::format("{:#} {}", p1, p2) << "\n";
    
    return 0;
}
*****************************      
AÇIKLAMA :
*****************************     
CEVAP : {2, 6} (3, 5)
*****************************


vformat_to
  • compile-time da belli olan formatlama string için kullanılır.



vformat
  • run-time da belli olan formatlama string için kullanılır.


template<typename... Args>
inline void println(const std::format_string<Args...> fmt, Args&&... args)
{
    std::cout << std::vformat(fmt.get(), std::make_format_args(args...)) << '\n';
}
 
int main()
{
    println("{}{} {}{}", "Software", ',', "C++", -1 + 2 * 3 * 4);
}

 
 
 

Recent Posts

See All
C++ Dilinde [[nodiscard]] attribute

C++’ta [[attribute]] (öznitelik) mekanizması, kod hakkında ek bilgi sağlayarak derleyicinin uyarılar vermesine, belirli optimizasyonlar...

 
 
 
C++ Dilinde constinit

C++20'de tanıtılan önemli bir özellik `constinit`'dir; bu özellik, statik depolama süresine sahip değişkenlerin derleme zamanında...

 
 
 

Comments


bottom of page