C++ Dilinde std::format_to
- 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);
}
Comments