The second paragraph talks about setting a #define before including a header, as if this is still the 90's.
The second paragraph talks about setting a #define before including a header, as if this is still the 90's.
I'm not shitting on the library in general, I'm saying the second paragraph disproves the title.
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.
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/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...
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.
#define definitely is not "modern". If nothing else it'll set you up for having problems modularizing it in the future.
I'm not talking about "The simplest option that comes to mind", but "modern C++".
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.
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.
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.
I have seen many many well-intentioned "but surely this time it's the best solution", where no, it's just a time bomb.