Now that if constexpr
is part of C++17, is it a good replacement for macros when writing platform dependent code and similar?
I'm wondering, because I really do not like macros, and would like to use them only for include guards and includes.
// those variables should be given by the compiler
constexpr unsigned int __os = 0x1; // current os
constexpr unsigned int __os_win = 0x1; // Windows
constexpr unsigned int __os_linux = 0x2; // Linux-flavors
constexpr unsigned int __os_apple = 0x4; // Mac os
void print_os() {
if constexpr (__os == __os_win)
std::cout << "You're on Windows!\n";
else if constexpr (__os == __os_linux)
std::cout << "You're on a Linux OS!\n";
else if constexpr (__os == __os_apple)
std::cout << "You're on Mac OS!\n";
}
instead of the current solution:
void print_os() {
#ifdef _WIN32
std::cout << "You're on Windows!\n";
#elif __linux__
std::cout << "You're on a Linux OS!\n";
#elif __APPLE__
std::cout << "You're on Mac OS!\n";
}
Both ways do not generate code for the other platforms when compiled, so they are technically the same, and as such, I would prefer the constexpr
way (if it were possible).
Would this be a feasible request for compilers to implement the constexpr
variables from above? I couldn't find any feature request and implementation for both gcc and clang, so there must be a reason why they don't want to implement the first way. Why is that so?
#define directives create macro substitution, while constexpr variables are special type of variables. They literally have nothing in common beside the fact that before constexpr (or even const ) variables were available, macros were sometimes used when currently constexpr variable can be used.
constexpr is a new C++11 keyword that rids you of the need to create macros and hardcoded literals.
constexpr if can be used to replace several tricks that were already done: SFINAE technique to remove not matching function overrides from the overload set. you might want to look at places with C++14's std::enable_if - that should be easily replaced by constexpr if . Tag dispatch.
In a constexpr if statement, the value of condition must be a contextually converted constant expression of type bool. If the value is true, then statement-false is discarded (if present), otherwise, statement-true is discarded.
A year after posting this question I now know why this is not a good idea. It's because the two are not actually equivalent.
if constexpr
is just a facility that doesn't instantiate the discarded branch. That's it. This means that code like:
void draw() {
#if LINUX
ncursesDrawWhatever();
#elif WINDOWS
Win32Draw();
#endif
}
(which is perfectly fine right now) is not equivalent to:
void draw() {
if constexpr (__linux)
ncursesDrawWhatever();
else if constexpr (__win)
Win32Draw();
}
because on both platforms the two functions need to be available (and on the preprocessor version they do not). In this case the constexpr
is completely redundant because it does nothing. Having to define both functions on both platforms just for one not being used is a bit of a pain, which is why the preprocessor was used in this way in the first place!
Probably because you haven't written one. These are fairly new things in the language. It takes time for an idea like that to filter down to actual code that's implemented and changes in how things are done.
As an example, I went through the Python asyncio
package, and despite the creation of async
and await
keywords in the language specifically to support the use-cases of this package, it uses them in very few places and uses the @coroutine
decorator most places still. This wasn't really too surprising.
So, post the feature request. Ask for some nice os testing constants that can be used with constexpr
conditionals. Or maybe even commit to digging into the library to implement them yourself. The feature is less than 2 years old. So it shouldn't be a surprise this hasn't been done yet.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With