memory_order::relaxed < cv_status::timeout is true
No it isn't. https://godbolt.org/z/bz7EhMhMT
HN user
memory_order::relaxed < cv_status::timeout is true
No it isn't. https://godbolt.org/z/bz7EhMhMT
Except that, as mentioned in TFA, as currently proposed it's possible to say
#if SOME_PREPROCESSOR_JUNK
import foo;
#else
import bar;
#endif
This has legitimate use cases, say #ifdef WIN32
import mymodule.windows
#else
import mymodule.posix
#endif
So in reality build systems will be required to invoke at least the preprocessor to extract dependency information.AFAIK the modules support in the Build2 build system does exactly this, and in fact caches the entire preprocessed file to pass to the compiler proper later.
The presence of template specialisations and constexpr functions means that the GP is right here; you cannot decide whether an arbitrary piece of C++ is syntactically valid without instantiating templates and/or interpreting constexpr functions. Consider
template <int>
struct foo {
template <int>
static int bar(int);
};
template <>
struct foo<8> {
static const int bar = 99;
};
constexpr int some_function() { return (int) sizeof(void*); };
Now given the snippet foo<some_function()>::bar<0>(1);
then if some_function() returns something other than 8, we use the primary template and foo<N>::bar<0>(1) is a call to a static template member function.But if some_function() does return 8, we use the specialisation and the foo<8>::bar is an int with value 99; so we ask is 99 less than the expression 0>(1) (aka "false", promoted to the int 0).
That is, there are two entirely different but valid parses depending on whether we are compiling on a 32- or 64-bit system.
Parsing C++ is hard.
EDIT: Godbolt example: https://godbolt.org/z/yR3YHW
Why on earth would you do this?
Good question! :)
It actually started out as a learning exercise -- I didn't (and still don't) know much about ray tracing, and so I thought it would be good to study a simple example by translating it from a language I didn't know (TypeScript) to one I was more familiar with.
This involved writing a simple vec3 class, and it seemed natural to make that constexpr. Then as I went through I realised that many more functions could be made constexpr too. And then if I hacked together some (admittedly very poor) replacement maths functions, even more of it could be constexpr...
At this point, it became a challenge to see whether I could make the whole thing run at compile-time. The only tricky part was avoiding virtual functions -- I'd originally naturally translated TypeScript "interface"s into C++ abstract classes. I ended up using two different approaches: firstly using std::variant and std::visit (the any_thing class in the source code), and secondly using a struct of function pointers (for the surfaces) -- because while virtual calls aren't allowed in constexpr code, calls via a function pointer are just fine.
In the end, I was pretty satisfied that I'd managed to push constexpr as far as I could take it. I had intended to blog about it, but never got round to it ... and now 18 months later someone has saved me the job by posting it to HN anyway :)
While constexpr was introduced in C++11, it was initially very limited -- a constexpr function could only consist of a single return statement, for example. It was only in C++14 that things like variable declarations and loops were allowed, and constexpr programming became practical.
Were there particular features of 17 that you were able to benefit from?
I used std::variant from C++17 for polymorphism, as a workaround for the fact that you can't have constexpr virtual functions (these have since been proposed for C++20). I also used `std::optional` when testing for intersections between a ray and a "thing", but it would have been possible to structure the code in such a way that this wasn't necessary (for example, by using a bool return value and an out parameter).
Lastly, I used constexpr lambdas (new in C++17) though again, it would have been possible to do things differently so these weren't required -- and indeed I did have to work around the fact that Clang (at the time) didn't support evaluating capturing lambdas at compile-time.
6. A constexpr function is guaranteed to have no undefined behaviour (when evaluated at compile time, anyway)
Author here. I wrote this on a rainy weekend last year and mostly forgot about it, so it was a bit of a surprise to see it pop up on HN this morning!
Happy to answer any questions (including "why on earth would you do this?") :)
I admit I clicked this thinking it was going to be about junk food.