3 ms·
Of 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_com
by quietbritishjim 5y ago
Of 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.
- knorker 5y agoIt's not philosophical, as it is code generation. The compiler doesn't see the #define. Which means the same source can be rebuilt with different defines and create hilarious undefined behavior. This also means that there's no way to create a library that supports debug and not debug. And of course no ability for the user of the library to select this at runtime. Yes, in the world of everything being compiled statically every single time (ala Google's monorepo) this can work, but code generation creates a HUGE number of gotchas, many of which are subtle. > But I hope it clarifies that they're the same thing. There're not, though. void* is "the simplest option that comes to mind", but where a template solution is available, safer, and clearer, it's not "modern C++" to have code with void* all over the place. "Easier" has nothing to do with it. There are many features in this fine library where the authors have put in effort to make it nicer, instead of just doing the easiest and quickest to implement.
- quietbritishjim 5y ago> void* is "the simplest option that comes to mind", but where a template solution is available, safer, and clearer, You're just playing silly semantics with "simplest" here. I meant that #define is genuinely the best overall solution to this particular problem, for the reasons I already gave. Whereas in void* vs templates, templates are genuinely the best overall solution.
- knorker 5y ago#define makes things worse in almost all cases. It's extremely rare to see it done right, as opposed to just being the path of least resistance, that builds up tech debt where things break in hilarious ways. I have seen many many well-intentioned "but surely this time it's the best solution", where no, it's just a time bomb.