Last active
February 25, 2025 10:50
-
-
Save dk949/0b1d14bec6eebdc9c3270c73d4d2ad72 to your computer and use it in GitHub Desktop.
C++20 sensible print macros. Uses std::format (including vector formatting). See "Usage" at the top of the file.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#ifndef UT_PRINT_HPP | |
#define UT_PRINT_HPP | |
/* Usage: | |
``` | |
// std >= c++20 | |
auto number = 42; | |
ut_print("the number is {}", number); | |
``` | |
output to stdout: the number is 42 | |
`ut_eprint` does the same but writes to stderr | |
`ut_fprint` is the same but takes a FILE* as the first argument and writes to that | |
`ut_println`, `ut_eprintln` and `ut_fprintln` append a newline to the end of the | |
format string | |
``` | |
#define UT_PRINT_PCVIEW | |
#include "print.hpp" | |
std::vector v{1,2,3,4}; | |
ut_print("v is {}", ut::PCView(v)); | |
``` | |
output to stdout: v is [1, 2, 3, 4] | |
Should work on any container that implements the PrintableContainer concept. | |
Tested on `std::vector`, `std::array` and `std::list`. | |
``` | |
// std >= c++23 | |
#define UT_USE_STD | |
auto number = 42; | |
ut_print("the number is {}", number); | |
``` | |
output to stdout: the number is 42 | |
Printing is done using the std::print/std::println functions, which have a | |
chance of being more performant than std::puts(std::format). | |
``` | |
#define UT_STD_ONLY | |
#include "print.hpp" | |
std::vector v{1,2,3,4}; | |
std::print("v is {}", ut::PCView(v)); | |
``` | |
output to stdout: v is [1, 2, 3, 4] | |
This disables the ut_* macros and enables UT_PRINT_PCVIEW | |
Allows container printing with std::print | |
Note: Using std::format can significantly impact compile times. Here are the | |
times it took to compile a program formatting 10 different types using `printf`, | |
`std::cout` and `ut_println`. | |
Compile times (g++ -O3): | |
| printf | cout | ut_println(std::format) | | |
| ~0.1s | ~0.5s | ~3.5s | | |
License: see end of file | |
*/ | |
#ifdef UT_STD_ONLY | |
# ifndef UT_USE_STD | |
# define UT_USE_STD | |
# endif | |
# ifndef UT_PRINT_PCVIEW | |
# define UT_PRINT_PCVIEW | |
# endif | |
#endif | |
#include <stdio.h> | |
#include <format> | |
#ifdef UT_USE_STD | |
# include <print> | |
#endif | |
#ifdef UT_PRINT_PCVIEW | |
# include <concepts> | |
# include <memory> | |
namespace ut { | |
template<typename C> | |
concept PrintableContainer = requires(C c) { | |
{ std::begin(c) } -> std::forward_iterator; | |
{ std::end(c) } -> std::sentinel_for<typename C::iterator>; | |
{ std::empty(c) } -> std::convertible_to<bool>; | |
std::format("{}", c.front()); | |
} | |
&&std::same_as<std::remove_cvref_t<decltype(std::declval<C>().front())>, typename C::value_type>; | |
// Printable container view | |
template<PrintableContainer C> | |
struct PCView { | |
using value_type = C::value_type; | |
C const &view; | |
PCView(C const &v) noexcept | |
: view(v) { } | |
}; | |
} // namespace ut | |
template<typename R, class CharT> | |
struct std::formatter<ut::PCView<R>, CharT> : public std::formatter<typename ut::PCView<R>::value_type, CharT> { | |
template<class FormatContext> | |
auto format(ut::PCView<R> vv, FormatContext &fc) const { | |
auto out = fc.out(); | |
out = std::format_to(out, "["); | |
if (!std::empty(vv.view)) { | |
out = std::format_to(out, "{}", vv.view.front()); | |
for (auto it = std::next(std::begin(vv.view)); it != std::end(vv.view); ++it) { | |
out = std::format_to(out, ", {}", *it); | |
} | |
} | |
return std::format_to(out, "]"); | |
} | |
}; | |
#endif | |
#ifndef UT_STD_ONLY | |
# ifdef UT_USE_STD | |
# define ut_fprint(file, fmt, ...) std::print(file, fmt __VA_OPT__(, ) __VA_ARGS__) | |
# define ut_fprintln(file, fmt, ...) std::println(file, fmt __VA_OPT__(, ) __VA_ARGS__) | |
# else | |
# define ut_fprint(file, fmt, ...) std::fputs(std::format(fmt __VA_OPT__(, ) __VA_ARGS__).c_str(), file) | |
# define ut_fprintln(file, fmt, ...) ut_fprint(file, fmt "\n", __VA_ARGS__) | |
# endif | |
# define ut_eprint(fmt, ...) ut_fprint(stderr, fmt __VA_OPT__(, ) __VA_ARGS__) | |
# define ut_eprintln(fmt, ...) ut_fprintln(stderr, fmt __VA_OPT__(, ) __VA_ARGS__) | |
# define ut_print(fmt, ...) ut_fprint(stdout, fmt __VA_OPT__(, ) __VA_ARGS__) | |
# define ut_println(fmt, ...) ut_fprintln(stdout, fmt __VA_OPT__(, ) __VA_ARGS__) | |
#endif // UT_STD_ONLY | |
/* | |
This is free and unencumbered software released into the public domain. | |
Anyone is free to copy, modify, publish, use, compile, sell, or | |
distribute this software, either in source code form or as a compiled | |
binary, for any purpose, commercial or non-commercial, and by any | |
means. | |
In jurisdictions that recognize copyright laws, the author or authors | |
of this software dedicate any and all copyright interest in the | |
software to the public domain. We make this dedication for the benefit | |
of the public at large and to the detriment of our heirs and | |
successors. We intend this dedication to be an overt act of | |
relinquishment in perpetuity of all present and future rights to this | |
software under copyright law. | |
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | |
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | |
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. | |
IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR | |
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, | |
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR | |
OTHER DEALINGS IN THE SOFTWARE. | |
For more information, please refer to <https://unlicense.org> | |
*/ | |
#endif // UT_PRINT_HPP |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
macros for printing using `std::format` in c++20 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment