{"id":22366717,"url":"https://github.com/vaeth/osformat","last_synced_at":"2025-07-22T05:35:28.503Z","repository":{"id":141994321,"uuid":"84190294","full_name":"vaeth/osformat","owner":"vaeth","description":"A C++ library for a typesafe printf/sprintf based on \u003c\u003c conversion","archived":false,"fork":false,"pushed_at":"2021-06-13T11:34:56.000Z","size":46,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-07-10T09:30:42.266Z","etag":null,"topics":["cplusplus","ostream","printf","typesafe"],"latest_commit_sha":null,"homepage":"","language":"C++","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/vaeth.png","metadata":{"files":{"readme":"README.md","changelog":"ChangeLog","contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":"AUTHORS","dei":null,"publiccode":null,"codemeta":null}},"created_at":"2017-03-07T11:14:44.000Z","updated_at":"2021-06-13T11:34:58.000Z","dependencies_parsed_at":null,"dependency_job_id":"ddbdbb54-c1d8-4519-9f7d-69e5e13fa953","html_url":"https://github.com/vaeth/osformat","commit_stats":null,"previous_names":[],"tags_count":8,"template":false,"template_full_name":null,"purl":"pkg:github/vaeth/osformat","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vaeth%2Fosformat","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vaeth%2Fosformat/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vaeth%2Fosformat/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vaeth%2Fosformat/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/vaeth","download_url":"https://codeload.github.com/vaeth/osformat/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vaeth%2Fosformat/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":266434113,"owners_count":23927906,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-07-22T02:00:09.085Z","response_time":66,"last_error":null,"robots_txt_status":null,"robots_txt_updated_at":null,"robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["cplusplus","ostream","printf","typesafe"],"created_at":"2024-12-04T18:15:23.526Z","updated_at":"2025-07-22T05:35:28.492Z","avatar_url":"https://github.com/vaeth.png","language":"C++","readme":"# osformat\n\nA C++ library for a typesafe printf/sprintf based on \u003c\u003c conversion\n\n(C) Martin Väth (martin at mvath.de).\nThis project is distributed under the terms of the\nGNU General Public License v2.\nSPDX-License-Identifier: GPL-2.0-only\n\nThis is a typesafe `printf`/`fprintf`/`snprintf` type library for C++.\nThe typesafety is obtained by using the standard `ostream`'s `\u003c\u003c` conversions.\nIt adds features which would not be available if one would use a plain ostream:\n\n1. It is usable with foreign translations when words need to be reordered.\n   This also applies to the case when the provided arguments must be\n   reordered or even repeated for certain languages.\n\n2. It does not cluster global modifiers of ostreams. For instance, output of a\n   float number in a certain notation over `std::cout` would require to set\n   such global modifiers.\n\n3. It provides a simple conversion to strings with a more convenient syntax\n   than by using `std::ostringstream`.\n\nThe library's functionality covers essentially `std::ostream`,\n`boost::format`, `absl::StrFormat`, and various independent implementations of\nso-called __StringPrintf__ or typesafe C++ printf variants like\nhttps://github.com/c42f/tinyformat or `src/eixTk/formated.h` from the\n__eix__ project.\n(See the section __History and Contributions`` for a list of related projects).\n\nNote that if the dependency cost is acceptable, the author would recommend\nto use instead `absl::StrFormat` (see https://abseil.io/docs/cpp/guides/format)\nsince the latter allows even compile-time checking of the arguments.\n\n## Some Features by Examples\n\n- `osformat::SayError(\"foo has value “%s”\") % foo;`\n\n  Similar to `std::cerr \u003c\u003c \"foo has value “\" \u003c\u003c foo \u003c\u003c \"“\" \u003c\u003c std::endl;`\n  or like `fprintf(stderr, \"foo has value “%s”\\n\", foo) \u0026\u0026 fflush(stderr)`\n  (but in contrast to the latter being typesafe, e.g. foo can be a number)\n\n- `osformat::Print(_(\"“%2$s“ has size %s\")) % filesize % file;`\n\n  Works if order has to be exchanged for foreign translations:\n  A foreign translator can translate the string into e.g. `%s Bytes in „%s“`\n  As customary by such internationalizations, only the `_()` function has to\n  return the translated form: No code changes are necessary!\n\n- `osformat::Print(\"A %1$s is a %1$s\") % \"rose\";`\n\n  The same argument can be accessed several times.\n  The output is `A rose is a rose`.\n\n- `osformat::Print(\"%1$s = %1$#x\") % 15;`\n\n  The same argument can be accessed repeatedly with different\n  modifiers/specifiers. Output is `15 = 0xf`.\n\n- `osformat::Print(\"%S %S\") % 17 % std::string::npos;`\n\n  A conversion usually not provided by `\u003c\u003c`:\n  Output is `17 std::string::npos`\n\n- `std::string r = osformat::Format(\"Result %*d\") % width % number;`\n\n  The minimal width can be specified by an indirect modifier, similar to\n  the POSIX `printf` function.\n\n- `osformat::Format(\u0026r, \"%2$*1$d\") % width % number;`\n\n  `r.append(osformat::Format(\"%2$*1$d\") % width % number);`\n\n  The previous two lines do the same thing: Appending to r.\n\n- `std::cout \u003c\u003c osformat::Format(\"%*2$.*E\") % width % precision % (1./7);`\n\n  The global flags for std::cout remain unchanged: Everything is local\n\n- `std::string number_as_text = osformat::Format() % (1./7);`\n\n  An omitted format acts like `%s` but is almost as efficient as\n\n  `std::string number_as_text = (std::ostringstream() \u003c\u003c (1./7)).str();`\n\n- `std::cout \u003c\u003c osformat::Print(\"%s \", osformat::Special::Flush()) % foo;`\n\n  Similar to\n\n  `std::cout \u003c\u003c foo \u003c\u003c \" \" \u003c\u003c std::flush \u003c\u003c foo \u003c\u003c \" \" \u003c\u003c std::flush;`\n\n  (if `std::ios_base::sync_with_stdio` is set).\n\n  Explanation: The first output (with flushing) to stdout occurs when the\n  `osformat::Print` object is constructed. The second output (with flushing)\n  occurs when the constructed object is sent to `std::cout`.\n\nWhat cannot be seen in these examples:\nThere is a runtime test for output errors (with aborting in case of errors;\na further argument can be provided to \"catch\" errors in a variable instead.)\n\n\n## Description\n\nEssentially, an `osformat::Format` class (and inherited classes) are provided.\nIts basic functionality is the constructor which can be used as follows:\n\n`osformat::Format([success,] [output,] [format,] [flags]) % arg1 % arg2 % ...`\n\nDepending on the parameters, the constructor directly appends output to a\nstring, sends it to `FILE`, or to an `std::ostream`.\n\nIt is admissible to postpone some or all of the `%` operations, but until all\narguments specified by format are passed, the object is in an error state.\nThe generated `osformat::Format` object is copyable, but the copy will not\naccept any further `%` operations (and thus remain in the error state if not\nall arguments have been passed before copying). When C++11 is used, the object\nis movable (including the state of postponed `%` operations).\n\nThe finished object (once all arguments have been passed) can be converted\ninto a string or sent with \u003c\u003c into an ostream and also has some further\nmethods described in a separate section __Further Methods__.\nEssentially, the finished object behaves like a string, but when sent to\noutput it also does automatic error checking (in a way determined by the\nconstructor) and possibly flushes the streams. (Both can be modified later on).\n\nThe types of the parameters of the above constructor are:\n\n- `bool *success`\n\n  If specified, sets success to true/false if there was no/some error.\n  If NULL, errors are tacitly ignored.\n  If not specified, in the error case the constructor prints a diagnostic\n  message to stderr and calls std::abort()\n  Note the the pointer (and whether it is provided) is stored in the object\n  also for all further operations with the object. There is a special methods\n  set_success() to modify this pointer or to enable/disable the std::abort()\n  handling.\n\n- `std::string *output`\n- `FILE *output`\n- `std::ostream\u0026 output`\n\n  If specified and not NULL, the output is appended to the string,\n  sent to the FILE or output to the ostream, respectively.\n\n- `const char *format`\n- `const std::string\u0026 format`\n- `char format`\n- `bool format`\n\n  If format is true or omitted, it is treated like `%s` but more efficient.\n  If format is false, it is treated like `` (empty string) but more efficient.\n  Details of the format are specified in the section __Format__.\n  It describes in a manner similiar to the `printf` format how the\n  arguments are to be interpreted. It is a design decision that only those\n  finer `printf` features are available which can easily be mapped to\n  `std::ostream` analogues (perhaps with simple post-/preprocessing):\n  It is not attempted to convert numbers without any support from STL.\n  Moreover, due to C++ language restrictions, there is a restriction on the\n  order of arguments: All indirect modifier arguments must not be specified\n  after the corresponding argument.\n  To avoid any issues with possible translations of the format string into\n  another language, it is therefore recommended, to first specify all the\n  arguments of base, fill, precision, or fieldwidth before specifying any\n  further actual arguments.\n\n- `osformat::Special flags`\n\n  This parameter can be generated with one of the static functions\n\n  - `osformat::Special::None()`         // Default: Nothing special\n  - `osformat::Special::Newline()`      // Append a newline at the end\n  - `osformat::Special::Flush()`        // Flush after output\n  - `osformat::Special::NewlineFlush()` // Combine the previous two\n  - `osformat::Special::FlushNewline()` // dito, just an alternative name\n\n  The osformat::Special type behaves similar to a bitmap type and provides the\n  binary operations `|` `\u0026` `^` `~` `|=` `\u0026=` `^=`, but it cannot directly be\n  converted to or from a numerical type to make the argument of the\n  `osformat::Format` class unambiguous. However, it might be assigned to/from\n  the underlying numerical type `osfp:Special::Flags`.\n  (Reason for the static functions:\n  C++98 does not know strongly typed enums, and static functions in C++98\n  are an issue for initialization order. Both could be avoided with C++11.)\n\nAll further arguments must match to the specified format string.\nDepending on the format string, they are usually converted into strings with\n\n`std::ostream \u003c\u003c arg`\n\nwhere `std::ostream` has a status determined by the format parameter.\nSome arguments might also be interpreted for setting this status.\n\nThere are some inherited classes:\n\n- `ostream::Print([success,] [format,] [flags]) % arg1 % arg2 % ...`\n- `ostream::PrintError([success,] [format,] [flags]) % arg1 % arg2 % ...`\n- `ostream::Say([success,] [format,] [flags]) % arg1 % arg2 % ...`\n- `ostream::SayError([success,] [format]) % arg1 % arg2 % ...`\n\nThese are analogous to `ostream::Format`. The only differences are:\n\n1. The output automatically goes to `stdout` (for `Print` and `Say`) or\n   `stderr` (for `PrintError` or `SayError`), respectively.\n2. For `Say`, `ostream::Special::Newline()` is always active\n   (i.e. even if flags are explicitly specified as `ostream::Special::None()`\n   or `ostream::Special::Flush()`, they are interpreted as if specified by\n   `ostream::Special:Newline()` or `ostream::Special::NewlineFlush()`,\n   respectively).\n3. For SayError the flags are `ostream::Special::NewlineFlush()`\n\n\n## Further Methods\n\nFor objects of type `ostream::Format` (or `Print`, `PrintError`, `Say`,\n`SayError`) the following further methods are available:\n\n- `void set_success(bool *success)`\n- `void set_Success()`\n\n  Defines that all further operations should signal an error to the\n  corresponding pointer. If success is `NULL`, the error is tacitly ignored.\n  If called without argument, all future errors will lead to the output of a\n  diagnostic message, followed by `abort()`.\n\n- `bool flush()`\n- `void flush(bool flush_state)`\n  Returns whether flush for output is active or sets its state to the specified\n  value, respectively.\n\n- `void Output(std::string *output)`\n- `void Output(std::ostream \u0026output)`\n- `void Output(FILE *output)`\n\n  Output the object to the specified output object. In case of a string,\n  the output is appended, and in case of `std::ostream` or `FILE`, it is\n  possibly flushed, depending on the state of `flush()`.\n  If an error occurs, the behaviour corresponds to that specified by the\n  constructor (or by the latest call to set_success if there was one).\n\n- `std::string str()`\n\n  returns the produced string\n\n- `operator std::string()`\n\n  alternatively to `str()`, the object can be cast into the produced string\n\n- `const std::string\u0026 StringReference()`\n\n  returns a reference to the produced string\n\n- `string::size c_str()`\n\n  a short form of `StringReference().c_str()`\n\n- std::string::size_type size()\n\n  a short form of `StringReference().size()`\n\n- `bool empty()`\n  A short form of `StringReference().empty()`\n\n- `std::size_t count()`\n\n  If previously output to a `FILE`, this returns the number of bytes actually\n  written. The value is unspecified if there was no previous output to FILE.\n\n- `void assign(const osformat::Format\u0026 source)`\n- `void assign(osformat::Format\u0026\u0026 source)`\n\n   Assigns the format the value of source, analogously to STL containers\n\n- `osformat::Error::Code error()`\n\n  Returns which error occured:\n\n  * `osformat::Error::kNone = 0`  // no error\n  * `osformat::Error::kWriteFailed`  // e.g. count() is lower than size()\n  * `osformat::Error::kFlushFailed`  // fflush of the FILE failed\n  * `osformat::Error::kTooManyArguments`\n  * `osformat::Error::kTooFewArguments`\n  * `osformat::Error::kTooEarlyArgument` // E.g. width value is too late\n  * `osformat::Error::kLocaleArgIsNoLocale`\n  * `osformat::Error::kLocaleMustNotBeOutput`\n  * `osformat::Error::kPrecisionArgIsNotNumeric`\n  * `osformat::Error::kWidthArgIsNotNumeric`\n  * `osformat::Error::kFillArgIsNotChar`\n\n  All other error codes refer to invalid definitions of the format string.\n\n  There is an `ost::Error` object which is purely static: It contains only the\n  above constants and the static methods\n\n  * `const char *osformat::Error::c_str(osformat::Error::Code)`\n  * `std::string osformat::Error::as_string(osformat::Error::Code)`\n  * `void osformat::Error::append(std::string *, osformat::Error::Code)`\n\n  which return/append an English description of the passed\n\n  `osformat::Error::Code`\n\n  The return value of `osformat::Error::c_str` is static and must not be freed.\n\nStrictly speaking, the following is not a method, but it is available\nfor the `osformat::Format object`:\n\n- `ostream\u0026 operator\u003c\u003c(const ostream::Format \u0026ostream, osformat::Format \u0026)`\n\n  When output into a stream, it behaves as output(ostream)\n\n\n## Format\n\nThe format is similar to that of printf as specified by POSIX.\nIt is composed of zero or more directives: ordinary characters, i.e.\nall except `%`, are taken unchanged. The character `%` introduces a conversion\nspecification which usually refers to arguments. The conversion specification\n\n- `%%`\n\n  is special: It refers to no argument and just outputs the % character.\n  Otherwise, a conversion specification has the form\n\n  `% [argnumber$] [modifiers] specifier`\n\n  (Here, spaces are used only for readability, and […] means as usual that\n  the corresponding … can be omitted.)\n\n  It is admissible that the same argnumber occurs several times.\n  If no argnumber is given, the smallest “free” number is used.\n  Here, a number is “free” if it is not used by any explicit argnumber\n  specifier within the format. Free numbers are given in the following order:\n  First, numbers occuring in indirect modifier arguments of the first conversion\n  specificiation are given (in the order given in the string),\n  Then the number for the first conversion specification is given.\n  Then the numbers occuring in the modifiers of the second conversion\n  specification is given, then the numbers for the second conversion, etc.\n  This corresponds to POSIX as close as possible.\n  Moreover, it ensures (if no explicit numbers are provided), that indirect\n  arguments setting modifiers do not occur after any corresponding argument\n  they should modify.\n  The latter is a restriction due to C++ syntax limitations: An argument must\n  not occur earlier in the argument list than any of its indirect modifiers.\n\n  To avoid problems for the case when the format string might come from a\n  foreign translation, it is therefore recommended to always order arguments\n  for modifiers in the beginning.\n\n  Modifiers consist of a single character, sometimes followed by an\n  argument part. The following modifiers exist:\n\n- `#`\n\n  Use `std::ios_base::showbase` when converting. This means that e.g. for\n  hexadezimal numbers an `0x` (or `0X`) is prepended.\n\n- `+`\n\n  Use `std::ios_base::showpos` when converting.\n  This means that a positive number is output with a leading `+` symbol\n\n` ` ` (space)\n\n  This is like `+` but replaces in the result the first `+` symbol\n  (if it exists) by a space character. An additionally specified `+` is\n  ignored.\n\n- `0`\n\n  Use 0 instead of space for padding. This is a shortcut for `_0`:\n\n-  `_`_character_ Use _character_ instead of the space character for padding.\n  The last character specified takes precedence.\n\n- `/`[_argnumber_`$`]\n\n  Use the character from the specified argument instead of\n  space for padding. The last character specified takes precedence.\n  This modifier takes precedence over `_‘character’`.\n  If it is specified several times, the highest argument number takes\n  precedence. If the _argnumber_`$` part is ommitted, the first free number is\n  chosen according to the rules explained above.\n\n- `-`\n\n  Use `std::ios_base::left` instead of `std::ios_base::right`\n  This means that the padding characters are added to the right\n\n- `:`\n\n  Use `std::ios_base::internal` instead of `std::ios_base::right`\n  This means that padding characters are added in the middle e.g. for monetary.\n  If both `-` and `:` are specified, the last occurence “wins”\n\n- _number_\n\n  (starting with 1-9). Use _number_ as the minimal field width for padding\n\n- `*`[_argnumber_`$`]\n\n  As _number_, but interpret the corresponding argument as the\n  number. If that argument is negative, its absolute value is considered,\n  and the modifier `-` becomes active.\n  This modifier overrides the _number_ modifier.\n\n- `.`_number_\n\n  Use _number_ as the precision\n\n- `.*`[_argnumber_`$`]\n\n  As `.`_number_, but use the corresponding argument to specify the\n  precision. If the _argnumber_`$` part is ommitted, the first free number is\n  chosen according to the rules explained above. This takes precedence over\n  the `.`_number_ argument.\n\n- `~`[_argnumber_`$`]\n\n  The corresponding argument must be a (const reference to a)\n  `std::locale` which should be used for the conversion.\n\nFor consistency with POSIX, it is recommended to use the\nfield list (plain number or `*`) as one of the last modifiers, and the\nprecision modifier (`.` or `.*`) as the very last one.\n\n\nFinally, here are the supported specifiers:\n\n- `s`\n\n  The argument can be almost anything: `ostream`'s `\u003c\u003c` is used to convert it.\n  Note that if you want to interpret a `char *` as a pointer (not as a string)\n  you should `static_cast` it into a `void *`.\n  Similarly, to force a character output, make sure to `static_cast` it into a\n  `char`.\n\n- `S`\n\n  as `s`, but there are special rules to make the output more readable:\n\n  * (a) A number of length `std::string::size_type` with value\n        `std::string::npos` is output as the string `std::string::npos`\n  * (b) The value `std::ios_base::boolalpha` is set so that the type `bool` is\n        output as `true` or `false`.\n  * (c) The value `std::ios_base::showpoint` is set to indicate the type of\n        floats\n\n- `d`\n\n  as `S` without (c)\n\n- `D`\n\n  as `d`, but additionally set `std::ios_base::uppercase`\n\n- `x`\n\n  as s, but set `std::ios_base::hex`.\n  So the output of numbers is usually in hex `0123456789abcdef`.\n\n- `X`\n\n  as `s`, but set `std::ios_base::hex | std::ios_base::uppercase`\n  So the output of numbers is usually in hex `0123456789ABCDEF`.\n\n- `o`\n\n  as `s`, but set `std::ios_base::oct`\n\n- `O`\n\n  as `s`, but set `std::ios_base::oct | std::ios_base::uppercase`\n\n- `f`\n\n  as `s`, but set `std::ios_base::fixed`\n\n- `F`\n\n  as `s`, but set `std::ios_base::fixed | std::ios_base::uppercase`\n\n- `e`\n\n  as `s`, but set `std::ios_base::scientific`\n\n- `E`\n\n  as `s`, but set `std::ios_base::scientific | std::ios_base::uppercase`\n\n- `a`\n\n  as `s`, but set `std::ios_base::fixed | std::ios_base::scientific`\n\n  This usually causes output of floats in internal hexadecimal representation\n\n- `A`\n\n  as `a`, but addtionally set `std::ios_base::uppercase`\n\n- `n`\n\n  dummy argument which is not output. This must be used if arguments are passed\n  but should not be printed: Otherwise, this would be considered an error.\n  A case when this might be useful is e.g. if a foreign translator of a\n  format string explicitly wants to omit certain arguments.\n\n\n## Corner Cases by Examples\n\n- `osformat::Format(\"%s %1$s\") % 'b' % 'a';`\n\n  This is valid and translates into `a b`!\n  The reason is that due to the specifier `%1$s`, the first argument is not\n  free in the moment when the number for the first specifier `%s` is decided:\n  Any specified argument number (even if it occurs in a later format string)\n  is not considered to be a free value for unnumbered arguments.\n\n  The motivation for the counterintuitive behaviour above is that you can\n  easily place modifier arguments at the beginning when the format is meant\n  to be translated into a foreign language:\n\n- `osformat::Format(_(\"%*1s %*2s\")) % width1 % width2 % string1 % string2;`\n\n  If you would have written\n\n- `osformat::Format(_(\"%*s %*s\")) % width1 % string1 % width2 % string2);`\n\n  the translater could not translate the string such that string1 is endowed\n  with width2. Indeed:\n\n- `osformat::Format(\"%1$*2$s\") % some_string % minsize);`\n\n  is not valid because the indirect modifier argument must not be passed after\n  the corresponding argument it refers to!\n  However, equality is allowed. The following is valid:\n\n- `osformat::Format(\"%1$*1$d\") % string_and_minsize;`\n\n  Modifiers for different arguments may also occur later,\n  although this practice is not recommended, because it may cause problems\n  when the string becomes translated into a foreign language which requires a\n  different order of values independent of modifiers:\n\n- `osformat::Format(\"A: %*s B: %*s\") % Awidth % Avalue % Bwidth % Bvalue;`\n\n\n## History and Contributions\n\nThe project was motivated by `src/eixTk/formated.h` from the __eix__ project\nwhich was originally implemented by Emil Beinroth \u003cemilbeinroth at gmx.net\u003e\nand later extended by Martin Väth \u003cmartin at mvath.de\u003e.\n\nAfter first reusing this class in some other projects and motivated by the\nnecessary `printf` hacks in some google projects, see e.g.\nhttps://google.github.io/styleguide/cppguide.html\nit became clear that an independent library might be useful.\n\nThe initial implementation was provided by Martin Väth \u003cmartin at mvath.de\u003e,\nwho is also so far the only maintainer.\n\nIn this original implementation, some ideas from the above projects were used.\nSome ideas of `boost::format` and https://github.com/c42f/tinyformat\n(author: Chris Foster) have been taken into account, but the `c` and `p`\nspecifiers are currently not supported, since this probably cannot be done\ncompiler independent and is not necessary when the user just casts.\nThere are several other independent implementations of similar type like\ne.g. `StringPrintf` propagated by Stefan Woerthmuller.\n\nOnly after writing the project, the author learnt about absl::StrFormat\n(see https://abseil.io/docs/cpp/guides/format) which allows even compile-time\nchecking of the arguments.\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fvaeth%2Fosformat","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fvaeth%2Fosformat","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fvaeth%2Fosformat/lists"}