Package: compile-time-printer
Compile-Time PrinterCompile-Time Printerprints values and types at compile-time in C++.Teasertest.cppcompile-time-printer--make test.cpp#include<ctp/ctp.hpp>template<autoI>constexprautofunc(inti){// Formatted output.ctp::printf("Hello {}!\n",ctp::type{I});// Standardized output.ctp::print(I+i,sizeof(I));returntrue;}constexprautotest=func<22>(20);.





Hello int!


42 4




                                          .Try it out online:https://viatorus.github.io/compile-time-printer/OverviewInstallationAPIHow it worksKnown limitationsLicenseInstallationRequires:Python >=3.6GCC >=7.4 and STD >=C++17To get started, install thepython tool:pip install compile-time-printerAfterwards, dump the CTP header file and include it in your project:compile-time-printer --dump-header-fileAlternative, you can install the header file via theconan package.Finally, run CTP with your build command.E.g. with g++ directly:compile-time-printer -- g++ -I. -fsyntax-only -std=c++17 -fpermissive test.cppE.g. with make:compile-time-printer -- make test.cppYou have to set the compiler flag-fpermissivein order to make it work.APIctp.hppctp::print([file descriptor,] arguments)Prints all arguments in a simple, standardized format. Each argument is separated by one space, ending with a line
break.intx=42;ctp::print("Hello",2.72,x);// "Hello 2.72 42\n"ctp::printf([file descriptor,] format, arguments)Formats and prints all arguments in the desired format without implicit line break.
Uses thepythons format string syntax.intx=42;ctp::printf("{:.1f}",3.14);// "3.1"ctp::printf("int: {0:d}; hex: {0:x};\n"// "int: 42; hex: 2a;\n""oct: {0:o}; bin: {0:b}",x);// "oct: 52; bin: 101010"ctp::stdoutorctp::stderrAvailable file descriptor to print to standard output stream or standard error stream.ctp::print(ctp::stdout,"Info");// stdout: "Info\n"ctp::printf(ctp::stderr,"Warning!\n");// stderr: "Warning!\n"ctp::type<Types>{}orctp::type{variables}Helper object which can be passed as an argument toprint/printfto output the type of the variables rather then
their values.intx=42;ctp::print(ctp::type<float>{},ctp::type{x});// "float int&\n"ctp::view(data begin, data end)orctp::view(data begin, data length)orctp::view(contiguous range)(implicit constructed)Helper object which can be passed as an argument toprint/printfto output a contiguous range.inta[]={1,2,3};ctp::print(ctp::view{a,1},ctp::view{a+1,a+3},a);// "[1] [2, 3] [1, 2, 3]\n"ctp::formatter<Type>Specialize structctp::formatterforType. Provide a functionconstexpr auto format(Type);returning a tuple like object. The first element must be a format string followed by the arguments.structFooBar{inti;};template<>structctp::formatter<FooBar>{staticconstexprautoformat(constFooBar&obj){returnstd::tuple{".i = {}",obj.i};}};constexprautotest=ctp::print(FooBar{42});// ".i = 42"ctp::forward(value)orctp::forward(function, arguments…)Helper to useprint/printfinstatic_assertand template parameters. SeeKnown limitations.compile-time-printerusage: compile-time-parser [optionals] [-- program args...]

Compile-time printer - prints variables and types at compile time in C++.

positional arguments:
  program               the program to compile the source (default: read from stdin)
  args                  the arguments for the command (default: [])

optional arguments:
  -h, --help            show this help message and exit
  --version             show program's version number and exit
  -r REMOVE, --remove REMOVE
                        removes matching regex from type info (default: [])
  -cr CAPTURE_REMOVE, --capture-remove CAPTURE_REMOVE
                        removes matching regex but keeps first capture-group from type info (default: [])
  --time-point          prints time point of each print statement (default: False)
  --no-color            disables colored error output stream (default: False)
  --hide-compiler-log   don't print unparsed compiler log (default: False)
  --dump-header-file    dumps the C++ header file to ctp/ctp.hpp (default: False)HighlightsUse--time-pointto get the time when the print statement has been reached. This can be used for benchmarking.0:00:00.236446 - Function one evaluated.
0:00:01.238051 - Function two evaluated.Use-rand-crto remove unnecessary information from types:namespaceabc::def{template<typenameT>structholder{};}usingH=abc::def::holder<int>;constexprautoi=ctp::print(ctp::type<H>{});// "abc::def::holder<int>"Output with-r"abc::def::":holder<int>Output with-cr".+<(.+)>":intHow it worksThe implementation ofprint/printfdoes nothing more than forcing the compiler to generate warnings
depending on the passed arguments. The python tool parses the warnings and converts them back to the actually
C++ arguments and outputs them (standardized or formatted) to stdout or stderr.So what does-fpermissivedo and why do we use it?-fpermissiveDowngrade some diagnostics about nonconformant code from errors to warnings. Thus, using -fpermissive will allow
some nonconforming code to compile.The nonconformant code we use in in the implementation is:constexprboolprint(inti,intj){intunused=i<<j;returntrue;}constexprautotest=print(10,34);10 << 34will cause an integer overflow which is not allowed, especially in a constant expression.
GCC will output the following interesting diagnostic error:<source>:2:20: error: right operand of shift expression ‘(10 << 34)’ is greater than or equal to the precision 32
of the left operand [-fpermissive]GCC evaluates the expressioni << jand gives a detailed message about the value ofiandj.
Moreover, the error will recur, even for the same input. Let us all thank GCC for supporting old broken legacy code.
With-fpermissivethis error becomes a warning and we cancontinue compiling.So everything we like to print at compile-time and can be broken down to fundamental types, can be outputted.Is it undefined behavior? Certainly. Will it format erase your hard drive? Probably not.Use it only for development and not in production!Known limitationsCompilerSince GCC is the only compiler I am aware of with detailed diagnostic warnings to recur, this tool can only work with
GCC.Prove me wrong.Instantiation of static_assert or template parameterIf a CTP statement is used while instantiate an expression triggered by astatic_assertor atemplate parameter,
the compilation will fail without a meaningful error message:<source>:55:19: error: non-constant condition for static assertion
    55 | static_assert(test());
       |               ~~~~^~Because-fpermissiveis a legacy option, it is not fully maintained anymore to work across all compile-time
instantiation.One workaround is to forward the expression to a constexpr variable instantiation:static_assert(ctp::forward<func()>);Check out thisexample.CachingThe result of a constexpr functions could get cached. If this happens, a CTP statement will only be evaluated once.
Try to generate additional noise to prevent this. Especially if this happens in unevaluated context.
Add additional changing input to the function call as (template) parameter. Also, GCC >=10 added-fconstexpr-cache-depth=8. Maybe a smaller value solves the issue.Check out thisexample.LicenseBSD-1 LICENSE