News for hackers. Stuff that matters.
Re:JSON for Modern C++ version 3.10.0 by knorker on Thursday August 19, 2021 @04:25AM (#28231598)
"Modern" C++.

The second paragraph talks about setting a #define before including a header, as if this is still the 90's.

Re:JSON for Modern C++ version 3.10.0 by nlohmann on Thursday August 19, 2021 @08:08AM (#28232780)
I would be happy to have a different way to decide if a member variable exists or not without touching anything else.
Re:JSON for Modern C++ version 3.10.0 by knorker on Thursday August 19, 2021 @02:38PM (#28237559)
Depending 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.

Re:JSON for Modern C++ version 3.10.0 by mike_hock on Thursday August 19, 2021 @04:49AM (#28231707)
Unfortunately, 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.
Re:JSON for Modern C++ version 3.10.0 by knorker on Thursday August 19, 2021 @07:22AM (#28232513)
It'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.

Re:JSON for Modern C++ version 3.10.0 by a-dub on Thursday August 19, 2021 @06:27AM (#28232199)
what's wrong with #define(s)?
Re:JSON for Modern C++ version 3.10.0 by einpoklum on Thursday August 19, 2021 @07:00AM (#28232364)
The 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.

Re:JSON for Modern C++ version 3.10.0 by a-dub on Thursday August 19, 2021 @04:25PM (#28238922)
interesting. 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)?
Re:JSON for Modern C++ version 3.10.0 by einpoklum on Tuesday August 24, 2021 @04:04AM (#28286162)
> 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/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...

Re:JSON for Modern C++ version 3.10.0 by quietbritishjim on Thursday August 19, 2021 @07:32AM (#28232565)
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()
Re:JSON for Modern C++ version 3.10.0 by knorker on Thursday August 19, 2021 @02:37PM (#28237541)
Well, 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.

Re:JSON for Modern C++ version 3.10.0 by quietbritishjim on Thursday August 19, 2021 @05:53PM (#28239837)
The 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.
Re:JSON for Modern C++ version 3.10.0 by knorker on Friday August 20, 2021 @04:23AM (#28243867)
A #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++".

Re:JSON for Modern C++ version 3.10.0 by quietbritishjim on Friday August 20, 2021 @05:35AM (#28244291)
> 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.

Re:JSON for Modern C++ version 3.10.0 by knorker on Friday August 20, 2021 @09:56AM (#28246002)
It'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.

Re:JSON for Modern C++ version 3.10.0 by quietbritishjim on Saturday August 21, 2021 @05:07AM (#28255407)
> 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.

Re:JSON for Modern C++ version 3.10.0 by knorker on Saturday August 21, 2021 @01:13PM (#28258665)
#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.