11 ms·
C++17 constexpr everything, or as much as the compiler can
- phkahler 9y agoWhat about debugging? If the code to generate the data is large and complex, how do you debug it when it only runs at compile time? Is the solution to start with two programs like the author and then merge them? That still seems like a maintainability issue.
- nurettin 9y agoYou could use something like #ifdef NDEBUG #define MY_CONSTEXPR #else #define MY_CONSTEXPR constexpr so when you are running the debug build, everything is debuggable.
- skrebbel 9y agoThat makes the compiler not complain when your constexpr isn't a valid constexpr.
- nurettin 9y agoUntil you make release
- AlexeyBrin 9y agoA constexpr function can be used with a non-constexpr argument in which case the compiler will keep the function in the compiled code and you can use it as a normal function. In the context of the linked article, take the first example and modify it, by reading a number at runtime with std::cin and call factorial or fibonacci with this number as an argument. Something like this https://godbolt.org/g/CT5M6f https://godbolt.org/g/CT5M6f
- dawg 9y agoIn D which has CTFE support since ages, you'd debug such functions by invoking them at runtime. https://tour.dlang.org/tour/en/gems/compile-time-function-evaluation-ctfe https://tour.dlang.org/tour/en/gems/compile-time-function-ev... There are also tools to print values at compile time. A compile time debugger for the CTFE interpreter is on our extended feature list for the current interpreter rewrite, but it's less of a priority atm.
- deleted 9y ago[deleted]
- ben-schaaf 9y agoSadly it's fairly easy to write a function that fails at compile time but runs fine at runtime. For those situations there's at least `pragma(msg,`
- jcelerier 9y ago> If the code to generate the data is large and complex, how do you debug it when it only runs at compile time? that's up to the compiler actually. For instance, in debug mode visual studio skips constexpr and does everything at runtime (which sucks if you depend on stuff being constexpr).
- masklinn 9y agoconstexpr don't have to run at compile-time, they can do so. So you can use regular tests/debugging to debug your function.
- 112233 9y agowhat about cases when regular debugging is printf/assert/static_assert?
- deleted 9y ago[deleted]
- humanrebar 9y ago> ...how do you debug it when it only runs at compile time? I prefer to unit test my constexpr logic with a bunch of static assertions in a cpp file. You could put them in with the code being debugged, but having them separate keeps the header files lighter weight with no real downside assuming you have CI or something set up.
- uncle_bob 9y agoC++ is never just C++. The build system for any C++ program includes both macro language and some form of make and/or make replacement. Explicitly generating tables at compile time and linking is bog standard at this point. Write a table generator program, have output create a table, splice in the order into make and/or make replacement. Sure it's three extra steps, but it's small steps that can be debugged. It also doesn't require any advanced compiler tricks that may or may not actually run at compile.
- Elv13 9y agoAnd have all embedded engineers raging because you just made cross compilation an order of magnitude harder.
- JdeBP 9y agoThe secret there, of course, is not to write the table generation program in C++. (-: In such circumstances, I find myself writing the table generator in shell script, REXX, or some such convenient language on the host system.
- minipci1321 9y agoSounds like opening a can of worms ... some developers will definitely opt for using a language which has "convenient" properties -- since the generator code is not running on the target platform, it has different constraints. And then one day, another dev team will face the task of porting rexx/perl/python/ocaml/you-name-it on a platform which has no capacities for that, or has no required depenedencies available, or neither.
- JdeBP 9y agoYou are making the error of thinking that one can only use one language, or that using the right language for a job is a bad thing; and you are making the error of thinking that build platforms did or do lack the capacity for generating source like this. These are platforms that have the capacity to run a C++ compiler; they have more than enough capacity to run tools like (say) od and sed.
- plq 9y agoGenuine question: Is there anything protecting us from an entirely new class of compiler bugs where the constexpr code and the compiled code behave differently? Is it at all possible?
- lazyjones 9y ago> Is it at all possible? Of course it is possible. Just consider all the registers, memory locations changed during the execution of such functions. Such side effects can affect behaviour of other code in the presence of compiler bugs.
- agumonkey 9y agoad hoc partial evaluation ?
- marcosdumay 9y agoWith explicit purity marks. I don't see how the C++ community will benefit from those, since the type of code that benefits is normally done in other languages. But I am certainly less creative than a community.
- reikonomusha 9y agoAll of this is easy in Common Lisp, which includes interactive compile-time debugging. You can use #., EVAL-WHEN, LOAD-TIME-VALUE, and other things to control evaluation time, and use the same, usual, interactive debugger that you use for runtime code, without any extra infrastructure or scaffolding. In C++, to debug failed constexpr’s, often, you have to make it a non-constexpr and debug at runtime.
- jcelerier 9y agoor you can just use a C++ repl like Cling ?
- reikonomusha 9y agoI’m not sure that’s even close to equivalent in execution-time debugging, and doesn’t work well with large, existing code bases with crafted build steps. These are transparent, non-issues in Common Lisp.
- HelloNurse 9y agoWhat the C++ repl does with constexpr functions would be unrelated to the code generated by the actual C++ compiler.
- marmaduke 9y agosince Cling is just Clang in a REPL, it seems like it would be good idea
- alexeiz 9y agoIs there anything not easy in Common Lisp?
- deleted 9y ago[deleted]
- lazyjones 9y agoI'm not sure this is really necessary. gcc and Apple's clang optimize the factorial code without "constexpr" and the fibonacci code might be an extreme case avoided by reasonable defaults for the numerous optimization parameters that can be adjusted: max-inline-recursive-depth max-inline-recursive-depth-auto Specifies the maximum recursion depth used for recursive inlining. For functions declared inline, --param max-inline-recursive-depth is taken into account. For functions not declared inline, recursive inlining happens only when -finline-functions (included in -O3) is enabled and --param max-inline-recursive-depth-auto is used. The default value is 8.
- teamhappy 9y agoYou should watch the talk that's mentioned in the article. They demo a constexpr json parser and a constexpr regex engine.
- lazyjones 9y agoI tried to watch the more interesting parts, it just doesn't seem like a useful approach to me to try to get the compiler to do this work at every compilation instead of the traditional approach of doing it once by generating C(++) code/structures from text/json data in my build. Especially with the "cognitive cost" and debugging issues involved.
- teamhappy 9y agoFair enough. I assumed you didn't consider the more complex use-cases because you mentioned compilers already doing this for small functions.
- CamperBob2 9y agoExactly. This technique will be high on my list of things to try the next time I find myself complaining that my compiler is too fast. Yet another C++ innovation that solves a problem that no one actually has.
- sehugg 9y ago
- andrepd 9y ago>In conclusion, at the time of this writing, you need to inspect the generated code of your compiler, if you want to be sure that something is really calculated at compile time. I don't get this. Why? Doesn't making a variable constexpr ensure it is a compile time value, or it will fail to compile?
- bilboa 9y agoApparently constexpr is like "inline". Just as the inline keyword doesn't actually guarantee that the compiler will inline a function, so constexpr doesn't require the compiler to precompute something, but rather just gives a hint to the compiler that you'd like it to if it can.
- grenoire 9y agoThere might be a case where you expected the compiler to constexpr something but it didn't. I can imagine cases where a heavy function getting called more than once, because you had expected it to be pre-computed.
- banachtarski 9y agoLiterally the second example shows a failing case for Clang 5 where GCC is able to statically compute it at compile time.
- andrepd 9y ago
- hzhou321 9y agoIf you use a general meta layer preprocessor such as MyDef, you may be able to construct macros that comes from evaluations of code in any languages (instead of restricted in eg. C++ with rather complicated compiler mechanics) A constexpr is a constant that is evaluated from a code at compile time, which is essentially just macros. Right? A general preprocessor that just do language agnostic code manipulations are not difficult but rather useful. Much complicated syntax sugar I see in the recent language development become unnecessary if a general preprocessor is in place (where syntactic sugar belong). I wonder why it is often not used.
- tambre 9y ago> A constexpr is a constant that is evaluated from a code at compile time, [...] It's rather a constant expression, which is quite a bit more than a mere constant. > [...] which is essentially just macros. Right? Macros are basically just text replacement. You can't write a macro and expect most compilers to execute the expressions and code inside the macro at compile-time. Some compilers may still to do that, but it's not very common for more complicated stuff. With constexpr you get a guarantee that the expression can be evaluated at compile-time and it gives quite a good hint to the optimizer to spend more time optimizing that portion of the code.
- hzhou321 9y agoWith a macro, you get guarantee of compile time evaluation, as well as compile time independent literal syntax double check. And you can do better than hint. You can double check the results explicitly. Since it's compile time evaluation, optimization is out of context.
- DamonHD 9y agoI am already a big fan of constexpr-ing everything that doesn't run away or make the compiler cry for our embedded application. Yes, we are building a substantial embedded system with (a constrained subset of; no heap, but some templates for example) C++ 11. Heretical, I understand.
- jotux 9y agoIn the last ~five years I've converted all my embedded software development to C++11, even projects on small microcontrollers (32kb flash, 8kb RAM). There are features I don't use but it's hard to imagine going back to C at this point.
- contrarian_ 9y agoOn the contrary, I've gone back to plain C for most projects and it's been a real relief after using C++11/14 extensively. So much accidental complexity just disappears. The compile times are much better, too. Can't wait to get a Threadripper CPU which should push the build even closer to feeling instant.
- petters 9y agoConstexpr everything can cause issues. Constexpr is a big part of a function interface. After you have applied it, you can never add logging etc.
- dkrikun 9y agoI personally do not understand the buzz around constexpr etc. All the real buziness is happening at runtime anyway and compilers already optimize code quite decently. The extra maintenance burden just doesn't pays off.
- failrate 9y agoI think you should review his premise: he is using constexpr to eliminate a separate exe, a data file, and code that loads and reads the data file at runtime. His maintenance burden goes down.
- mwkaufma 9y agoIt's like 'const' itself -- it's a tool for producing better error messages, not better final executables.
- jordigh 9y agoMan, meanwhile, D has compile-time function evaluation. D's compiler is really awesome. Most of the time, no special syntax is to evaluate things at compile time (perhaps just a "static" keyword here or there) and the rules are much simpler than C++'s. https://tour.dlang.org/tour/en/gems/compile-time-function-evaluation-ctfe https://tour.dlang.org/tour/en/gems/compile-time-function-ev...
- mehrdadn 9y agoI have yet to understand what information 'constexpr' conveys to the compiler that makes it necessary or useful.
- minipci1321 9y agoCertain things, when used in a routine, make computation impossible at compile time. If the routine is marked with 'constexpr', the compiler will verify that.
- mehrdadn 9y agoCouldn't it already do the exact same thing without constexpr? (And shouldn't it have already done that when optimizing? In fact for simpler expressions compilers already do this, right?) How does specifying constexpr help?
- minipci1321 9y agoBut I think you nailed it -- the compiler doesn't have to signal optimization "failures" back to the developer, but it has to for the constexpr case. It is not that the constexpr routine can be used at compile time, it is that it must be useable at compile time.
- mehrdadn 9y ago> But I think you nailed it -- the compiler doesn't have to signal optimization "failures" back to the developer, but it has to for the constexpr case. Is this true? Where do you see Clang emit a diagnostic in the example in the given article? (https://godbolt.org/g/HKcPFT https://godbolt.org/g/HKcPFT)
- minipci1321 9y agoYou seem to be right -- at least "no diagnostics required" is mentioned a few times in $10.1.5 of N4700. To be honest, my comment is not from the article in the example, but from my own experience, and that is mostly with GCC 7.2.
- WalterBright 9y agoD doesn't need constexpr. It's much simpler - any function whose value is needed at compile time is evaluated at compile time. For example: int square(int x) { return x * x; } const y = square(3); // evaluated at compile time int bar() { int[square(2)] array; // evaluated at compile time return square(3); // evaluated at run time } If a value is needed at compile time, and the function cannot be evaluated at compiler time (i.e. it relies on things like global variables not known at compile time) then a compilation error is issued. There isn't any ambiguity about whether it is evaluated at runtime or compile time - there is no "fall back" to run time if it can't be done at compile time.
- minipci1321 9y agoMaybe 'constexpr' has been added rather to express the intent (for example, for library development)?
- WalterBright 9y agoYou can annotate D functions as 'pure', which would have that effect, but purity is used for other reasons. Evaluating functions at compile time has another wrinkle in D - it is path dependent: int square(int x) { if (x < 100) return x * x; printf("oops\n"); return 0; } const int x = square(3); // works const int y = square(100); // fails at compile time I.e. the path taken through the function has to be pure, not every part of the function.
- danellis 9y agoWhat about values that aren't needed at compile time, but can be so optimized.
- Veedrac 9y agoD still has optimization passes.
- Doxin 9y agoRunning code at compile time in D is not an automatic optimization. Only code in certain constructs are ran at compile time, for example function calls in variable declarations or static if statements. Generally it's not something you even need to think about. This runs foo() at compile time: int bar=foo(); This runs foo() at runtime: int bar; void main(){ bar=foo(); }