3 ms·
"Modern" C++. The second paragraph talks about setting a #define before including a header, as if this is still the 90's.
by knorker 5y ago
"Modern" C++.
The second paragraph talks about setting a #define before including a header, as if this is still the 90's.
- mike_hock 5y agoUnfortunately, this antipattern has persisted way beyond the 90s. But, you know, if the only way the standard provides to achieve a certain goal is a shitty hack, people will use the shitty hack.
- a-dub 5y agowhat's wrong with #define(s)?
- einpoklum 5y agoThe compiler is blind to them, so they can't be reasoned about / carried forward anywhere / allowed for in one way or another. Moreover, because of `#define`s, the effect of including a file can be entirely different, so a compiler can never say "Oh, I know what's in this include file already, I don't need to include it again in other translation units". Of course #define's have many uses, and at present cannot be avoided entirely, but C++ has been making an effort to have other mechanisms put in place so as to obviate the use of #define's In particular, look for CppCon talks about Modules.
- a-dub 5y agointeresting. so traditionally the preprocessor has been used to work around incompatibilities across various compilers/platforms and to completely enable/disable features at compile time. what's the new thinking there? can you build big projects across clang/g++/intel without preprocessor workarounds now? has the number of viable compilers in use dropped and compatibility amongst those that live on increased? how about stuff like debugging/instrumentation? or is the current thinking on all that stuff to always build with all of it and enable/disable via runtime branch? (along with some argument that configuration at build time was more trouble than it's worth on modern spacious/fast machines)?
- einpoklum 5y ago> what's the new thinking there? In a nutshell: Using compile-time facilities which are within the language itself. Compilers will expose information about the platform, about themselves, etc. A couple of examples: * https://en.cppreference.com/w/cpp/utility/source_location https://en.cppreference.com/w/cpp/utility/source_location * https://en.cppreference.com/w/cpp/types/endian https://en.cppreference.com/w/cpp/types/endian > can you build big projects across clang/g++/intel without preprocessor workarounds now? Well, first of all, s/now/when C++20 is fully and widely adopted. Still, a good question. Possibly not? I'm not sure. But you would need a lot less of them than previously. > has the number of viable compilers in use dropped Not really. > and compatibility amongst those that live on increased? Well, if they're compatible with the standard, that says more than it used to. > how about stuff like debugging/instrumentation? Maybe if constexpr(in_debug_mode) ? Not sure. I'm not on the committee...
- knorker 5y agoIt's definitely not the only way, though. It can be a trade-off, but becoming less and less so. I'll admit to not looking at the implementation, but when you sell it as "modern" then it's not OK to do it for performance, for example. And almost every single use I've seen "for performance" actually has zero or negligible performance impact.
- quietbritishjim 5y agoOf course you'd get your compiler to globally define that symbol rather than literally using a #define. Assuming you're using CMake, that means using target_compile_definitions()
- knorker 5y agoWell, depending what it is you can also templatize, pass in lambdas, use inheritance, or whatever else you can think of. #define definitely is not "modern". If nothing else it'll set you up for having problems modularizing it in the future.
- quietbritishjim 5y agoThe feature in question is to enable a debug mode. That is very much the sort of thing that you want to control from your build system. I've already said how you'd do that with a #define, and you could easily hook that up to a CMake cache variable. How are you going to get CMake to control what base class / lambda / non-type template parameter gets used? The simplest option that comes to mind is to maintain two small separate source files in your application (which typedef to the appropriate template instantiation) and switch between them depending on the build parameter. Compared to an argument to the compiler to set a preprocessor definition, that would be a mess.
- knorker 5y agoA #define is just a source code generator run by the build system, with fewer steps. In my opinion the fact that it has fewer steps doesn't make it less of a mess. I'm not talking about "The simplest option that comes to mind", but "modern C++".
- quietbritishjim 5y ago> A #define is just a source code generator run by the build system, with fewer steps. OK, if you're getting philosophical, you're welcome to to think of the -D switch as being a type of source code generation. But there's a big practical difference. target_compile_definitions is one line in your CMakeLists.txt (two if you add a cache variable for it) and everyone can understand it instantly. Whereas creating a myappconfig.hpp.in and using configure_file() and #including it from all your actual source files (yuck) is much greater mental overhead both to create and maintain in practice. I know which I'd prefer. > I'm not talking about "The simplest option [available in modern editions of C++] that comes to mind", but "modern C++". I added a little to your quote there, forgive me. But I hope it clarifies that they're the same thing. If modern editions of C++ don't add any facilities that make it easier to do conditional compilation (chosen from your build system), then #define IS "modern C++". The fact that there are other ways of doing it, which you consider cleaner but are clearly impractical, is irrelevant. (I'm just talking about this particular usage where you #define one constant the same way everywhere. I've seen horrific tricks where you #define one way then #include, then #define something and #include again (yes there are no include guards). Clearly that isn't forgivable, whatever version of C++ you're using.) For the record, Rust has a nicer option for conditional compilation: feature flags. In principle a future version of C++ could adopt something similar, at which point #define really would disqualify that code from being "modern C++". But clearly that's not available in the most recent standard, or even planned in future standards AFAIK.
- nlohmann 5y agoI would be happy to have a different way to decide if a member variable exists or not without touching anything else.
- knorker 5y agoDepending on context of that question concepts and/or just SFINAE could help with that. I'm not shitting on the library in general, I'm saying the second paragraph disproves the title.