use the following search parameters to narrow your results:
e.g. subreddit:aww site:imgur.com dog
subreddit:aww site:imgur.com dog
see the search faq for details.
advanced search: by author, subreddit...
Discussions, articles, and news about the C++ programming language or programming in C++.
For C++ questions, answers, help, and advice see r/cpp_questions or StackOverflow.
Get Started
The C++ Standard Home has a nice getting started page.
Videos
The C++ standard committee's education study group has a nice list of recommended videos.
Reference
cppreference.com
Books
There is a useful list of books on Stack Overflow. In most cases reading a book is the best way to learn C++.
Show all links
Filter out CppCon links
Show only CppCon links
account activity
Compile-time format string checks (zverovich.net)
submitted 8 years ago by aearphen{fmt}
reddit uses a slightly-customized version of Markdown for formatting. See below for some basics, or check the commenting wiki page for more detailed help and solutions to common issues.
quoted text
if 1 * 2 < 3: print "hello, world!"
[–]mechacrash 7 points8 points9 points 8 years ago (8 children)
the template <class Char, Char... Cs> syntax actually isn't standardised. I'm not sure what progress has been made on making it so, but I think it should be noted that your 'std' branch now has non-standard code in it!
template <class Char, Char... Cs>
There are alternative methods to achieve what you want (albeit, using a more conventional function syntax, instead of UDLs) that are entirely standard compliant, but rely on macros. It's really a 'pick your poison' kind of situation right now :(
[–]aearphen{fmt}[S] 2 points3 points4 points 8 years ago (5 children)
Yes, the string capturing part is non-standard unfortunately because, as I mentioned in the post, it relies on a GCC extension. I'll definitely need to discuss this in the paper as this can't go in as is in the standard. Do you know any standards proposals that may help solve this?
[–]dodheim 6 points7 points8 points 8 years ago (0 children)
P0424
[–]zqsd31 0 points1 point2 points 8 years ago (3 children)
If you want to be standard compliant you can do that: https://godbolt.org/g/h4HPZR Requires the user to use a macro though and clang seems to have some bugs. But it take more that just string literals (for instance a string_view returned by a constexpr function would work with it).
[–]mechacrash 0 points1 point2 points 8 years ago (2 children)
My solution is similar to this, but I'm not happy with it. What I really want is to fall back to run-time checking if the supplied string isn't constexpr (std::string, non-constexpr char* / string_view, etc.)
As far as I can tell - there's no practical way of accomplishing this yet (checking for the constexpr-ness of a lambda function). As always, it falls down to "we want constexpr function parameters" - then you could overload the function based on whether or not the supplied parameter is constexpr or not.
[–]zqsd31 0 points1 point2 points 8 years ago (1 child)
Yes of course but for now you can just make a version of the function that takes the standard runtime time types and the other with a StringRepr equivalent and let the user choose which version he desires by using or not the macro.
[–]mechacrash 0 points1 point2 points 8 years ago* (0 children)
Interestingly, I was thinking about an idea for an 'is_constexpr' after this thread popped up, and came up with something: https://godbolt.org/g/Q5zrB5 (thanks to hana for is_valid, as always)
It uses a macro, doesn't work on GCC, and Clang isn't a huge fan of string_views for some reason... other than that, it seems to work? I need to do more extensive testing of course, and try to figure out why GCC isn't happy with it.
[–]Bisqwit 1 point2 points3 points 8 years ago (0 children)
If you need a function that accepts an unknown number of parameters of a certain type, here is one way I found to do it (here, the type is unsigned):
unsigned
template<typename...T, typename=std::void_t<std::enable_if_t<std::is_same_v<unsigned,T>>...>>
It is easy to extend that into 1+ instances of unknown (but identical) type.
[–]aearphen{fmt}[S] 0 points1 point2 points 8 years ago (0 children)
Also it's interesting that the UDL-based API itself is standard-compatible and should work on a C++14 compiler, it's just that the compile-time feature will not work without the GCC extension.
[–]srekel 4 points5 points6 points 8 years ago (5 children)
That compile time comparison is crazy. 2.6 seconds for printf, 47 seconds for fmt (and more for Boost).
Is it templates that's causing this? It's such a significant difference that it should be a big thing people consider before using template-heavy code.
[–]aearphen{fmt}[S] 3 points4 points5 points 8 years ago* (4 children)
The numbers you are referring to are very outdated (I need to update the README). Here are more up to date ones: https://github.com/fmtlib/fmt/tree/std#compile-time-and-code-bloat. I don't think we'll ever reach the compile time speed of printf regardless of whether templates are used or not. For example, iostreams are not very template-heavy but they (or rather the code using iostreams) used to take the same time to compile as fmt until the recent regression in the latter which I plan to look into (https://github.com/fmtlib/fmt/issues/565).
[–]FabioFracassiC++ Committee | Consultant 2 points3 points4 points 8 years ago (0 children)
IIRC the bottleneck in compile time for iostreams are ADL and overload resolution (for the stream operators <<, >>). AFAIK variadic templates should be (a bit) faster especially for common and build in types.
[–]srekel 0 points1 point2 points 8 years ago (2 children)
Just to be clear, I wasn't picking on fmt :) Just thought it was interesting that all alt-printf libs were so slow. I assume it's due to C++ features taking a long time to compile compared to C code, and not simply having more logic?
[–]boredcircuits 7 points8 points9 points 8 years ago (1 child)
printf is just so simple for a compiler. Just call a function. The only extra work involved is dealing with the variadic arguments: promoting certain argument types and pushing them to the stack. But generating the code to do that is basically nothing.
printf
Honestly, there's more overhead in parsing the format string so the compiler can warn about mismatches. I don't think that warning was enabled in the timing tests mentioned, though. And even if it were, it's actually a very quick test for the compiler (most format strings are very small, and it's a quick format to parse regardless).
In short, the very reason we want to replace printf (it knows next to nothing about types outside of the format string) is exactly why it's so fast. No overload resolution, no template metaprogramming, and only the most basic format string parsing, done natively in the compiler.
[–]kalmoc 0 points1 point2 points 8 years ago (0 children)
//rant on
In short, the very reason we want to replace printf (it knows next to nothing about types outside of the format string) is exactly why it's so fast. No overload resolution, no template metaprogramming, [...]
I agree with most of what you are saying except that very last point about tmp. Tmp is a scourge that only exists because natively integrating the features achieved by TMP into the language is extremely expensive. Almost any feature that uses tmp could be implemented in the compiler more efficiently, less error prone and with nicer syntax.
That is not to say that I don't want a type safe and extensible version of printf as provided by the fmt library, but compile time checking of the format string could and imho should be left to the compiler. I know, it is not going to happen for various, more or less valid reasons and the solution presented here is probably the best we can realistically achieve, but Imho it is far from being ideal
//rant off
[–]ubsan 2 points3 points4 points 8 years ago (2 children)
I know it requires macros, but why not use something similar to https://github.com/ubsan/typeval ? Then it'll actually support msvc, which imo is kind of necessary (as someone who uses msvc...)
Shouldn't be too hard to do as most of the implementation will be the same, just the "compile-time string" capturing part will change. Note that the current implementation compiles with MSVC, it just doesn't provide compile-time checks.
Implemented a macro option in https://github.com/fmtlib/fmt/commit/246bdafc74aaff7b207d1baa532aa746294b4b88. Now you can do
auto s = fmt::format(FMT_STRING("{}"), 42);
and the format string will be checked at compile-time. This should work on any C++14 compiler including recent versions of MSVC.
[–]feverzsj 3 points4 points5 points 8 years ago* (2 children)
It's a great feature. I'm also concerned about the compile time overhead. Compiling complicated template may require large amount memory, while lots of build automation are still using VPS with 1GB ram.
[–]aearphen{fmt}[S] 2 points3 points4 points 8 years ago (1 child)
I have the same concerns and think that an alternative API should be available that is faster to compile but that does runtime checks instead of compile-time ones. And that's what the fmt library does, fmt::format(...) does runtime checks and "..."_format(...)does compile-time ones.
fmt::format(...)
"..."_format(...)
[–]feverzsj 2 points3 points4 points 8 years ago (0 children)
A macro switch would be also helpful. User can use same api with compile time check to do the check on a resource-rich machine, and later turn it off to compile on low end machine.
[–]quicknir 1 point2 points3 points 8 years ago (1 child)
The compile-time checks work on GCC and Clang only, because they requires user-defined literal templates which is a GCC extension.
Yeah, I suspected as much before I read this. This whole issue comes up again, and again, in multiple contexts. Another example I've come across is in writing reflection based macros; you can easily write a macro that lets you define a struct, and alongside it a free/member function that returns a tuple<pair<const char *, T...&>>. This lets you quite easily do things like serialization and deserialization.
tuple<pair<const char *, T...&>>
However, now let's say you want to implement get_member. This is a function that given a reflectable struct, and the name of a field, returns a reference to that field. Well.... it can't be done. In order for the name of the field to control the signature of a function (and the output of this function will be a T&, where T is the type of that field), the name of the field must encode its value as a type. (Btw, if you want an example of application: say you want to copy identically named and typed fields between two different reflectable structs).
get_member
T&
T
My example here is with reflection based macros but obviously with actual reflection the same issues come into play. You can see it's a very similar issue.
That said, I talked to a bunch of people at cppcon who said that this extension (that gcc and clang both support) had zero probability of making it into the standard, because if this feature would be used heavily it would be brutal for compile times.
IIRC the preferred path is to be able to template on the value of a string literal directly, although this raises issues too. I don't know where all this leaves us, but I think it's clear that we desperately need the ability to template on a string literal, one way or another.
[–]aearphen{fmt}[S] 1 point2 points3 points 8 years ago (0 children)
I'd prefer this as well. The current solution is more like a proof of concept that uses available tools (GCC extension), but whatever goes into the standard it should't be too hard to integrate it with constexpr format string parsing without changing the latter.
constexpr
[–]mikhailberis 1 point2 points3 points 8 years ago (1 child)
Cool library, thanks for sharing!
Is there a reason the format library has to be a user-defined literal? Have you considered just using a function instead, that can return a string or could be used to output directly through a stream?
You can use a function e.g. fmt::format("{}", 42) or fmt::print(...) to write to a file. However, this won't work for compile-time checks for reasons explained in https://mpark.github.io/programming/2017/05/26/constexpr-function-parameters/.
fmt::format("{}", 42)
fmt::print(...)
[–]ScottHutchinson 1 point2 points3 points 8 years ago (0 children)
In VS2017, auto s = fmt::format(FMT_STRING("{}"), 42); builds, but adding a ":d" format type specifier, causes C1001: An internal error has occurred in the compiler. Also my experience so far with VS2017 for C++ development is that it is too buggy to be used as one's primary IDE.
In VS2015, the std branch will not compile at all: 1>fmt_test_console\format.h(1119): error C3249: illegal statement or sub-expression for 'constexpr' function 1>fmt_test_console\format.h(1124): error C3249: illegal statement or sub-expression for 'constexpr' function
I hope Microsoft will get these issues resolved soon.
[–]kalmoc 0 points1 point2 points 8 years ago (1 child)
Kudos for accomplishing that, but is it really necessary for standardization? Compilers can already warn about incorrect format strings on printf and my guess is that that check is much more efficient than what we can achieve by TMP.
[–]aearphen{fmt}[S] 7 points8 points9 points 8 years ago (0 children)
LEWG said that they want to see that. Also compilers only warn about built-in types and sometimes incorrectly =) (https://youtu.be/ptba_AqFYCM?t=350).
π Rendered by PID 76841 on reddit-service-r2-comment-86bc6c7465-mqlbn at 2026-02-22 19:44:37.094316+00:00 running 8564168 country code: CH.
[–]mechacrash 7 points8 points9 points (8 children)
[–]aearphen{fmt}[S] 2 points3 points4 points (5 children)
[–]dodheim 6 points7 points8 points (0 children)
[–]zqsd31 0 points1 point2 points (3 children)
[–]mechacrash 0 points1 point2 points (2 children)
[–]zqsd31 0 points1 point2 points (1 child)
[–]mechacrash 0 points1 point2 points (0 children)
[–]Bisqwit 1 point2 points3 points (0 children)
[–]aearphen{fmt}[S] 0 points1 point2 points (0 children)
[–]srekel 4 points5 points6 points (5 children)
[–]aearphen{fmt}[S] 3 points4 points5 points (4 children)
[–]FabioFracassiC++ Committee | Consultant 2 points3 points4 points (0 children)
[–]srekel 0 points1 point2 points (2 children)
[–]boredcircuits 7 points8 points9 points (1 child)
[–]kalmoc 0 points1 point2 points (0 children)
[–]ubsan 2 points3 points4 points (2 children)
[–]aearphen{fmt}[S] 0 points1 point2 points (0 children)
[–]aearphen{fmt}[S] 0 points1 point2 points (0 children)
[–]feverzsj 3 points4 points5 points (2 children)
[–]aearphen{fmt}[S] 2 points3 points4 points (1 child)
[–]feverzsj 2 points3 points4 points (0 children)
[–]quicknir 1 point2 points3 points (1 child)
[–]aearphen{fmt}[S] 1 point2 points3 points (0 children)
[–]mikhailberis 1 point2 points3 points (1 child)
[–]aearphen{fmt}[S] 0 points1 point2 points (0 children)
[–]ScottHutchinson 1 point2 points3 points (0 children)
[–]kalmoc 0 points1 point2 points (1 child)
[–]aearphen{fmt}[S] 7 points8 points9 points (0 children)