Add macros for conditional constexpr#152
Conversation
Codecov ReportBase: 97.39% // Head: 97.94% // Increases project coverage by
Additional details and impacted files@@ Coverage Diff @@
## master #152 +/- ##
==========================================
+ Coverage 97.39% 97.94% +0.55%
==========================================
Files 131 133 +2
Lines 10248 10865 +617
==========================================
+ Hits 9981 10642 +661
+ Misses 267 223 -44
Help us with your feedback. Take ten seconds to tell us how you rate us. Have a feature suggestion? Share it here. ☔ View full report at Codecov. |
| #define CORRADE_CXX14_CONSTEXPR constexpr | ||
| #else | ||
| #define CORRADE_CXX14_CONSTEXPR | ||
| #endif |
There was a problem hiding this comment.
There's already CORRADE_CONSTEXPR14 in Corrade/Utility/Macros.h, and I'd like the other two to follow a similar naming and be in the same header.
But also please see my comment in mosra/magnum#597 about having a special macro for C++14+ constexpr only if a "is constant evaluated" builtin is available.
There was a problem hiding this comment.
Alright. Seems like my original proposal wasn't sufficient for what we're trying to achieve. It's not too useful for any of CORRADE_CONSTEXPR{17,20,23} to be defined -- C++14 relaxed constexpr is already enough for anything Vector has to handle. But CORRADE_CONSTEXPR14 needs to reflect whether it works in practice (__cpp_constexpr is accurate here). Then we have several kinds of constexpr functions:
- C++11 semantics --
constexpr - constexpr with C++14 rules, no need for inline asm or intrinsics --
CORRADE_CONSTEXPR14 - ones that need SIMD --
CORRADE_CONSTEVAL14, #ifndefCORRADE_CONSTEVAL
The last case can be used like that:
template<typename T>
CORRADE_CONSTEVAL14 inline T foo(T x)
{
#ifdef CORRADE_CONSTEVAL
if CORRADE_CONSTEVAL
{
// do something traditional to 'x'
}
else
#endif
{
// do something funny to 'x'
}
}If you want to enable constexpr when lacking CORRADE_CONSTEVAL but when SIMD has been disabled, then it could be set to constexpr(true) as long as __cpp_if_constexpr >= 201606 holds (aka C++17).
There was a problem hiding this comment.
I think it's better to remove CORRADE_CONSTEVAL14 from this pull request and put it in Magnum with a name such as MAGNUM_VECTOR_CONSTEVAL14. It's too specialized for a global definition. Here it is for reference:
#ifdef CORRADE_CONSTEVAL
#define CORRADE_CONSTEVAL14 CORRADE_CONSTEXPR14
#else
#define CORRADE_CONSTEVAL14
#endifa727881 to
7220cb9
Compare
38044a3 to
5723da7
Compare
| */ | ||
| #if CORRADE_CXX_STANDARD >= 201402 | ||
| #if defined __cpp_constexpr && __cpp_constexpr >= 201304 || \ | ||
| defined CORRADE_TARGET_MSVC && _MSC_VER >= 1910 && CORRADE_CXX_STANDARD >= 201402L |
There was a problem hiding this comment.
Shouldn't this contain a bunch of parentheses, to ensure && and || are evaluated in the correct order? Same below.
Also, TIL that defined can be without parentheses. Nevertheless, could you add them there, just for consistency with all other occurences of defined()? Thanks.
What's the L needed for? I don't think it's essential. Or do you get some compiler warnings without?
There was a problem hiding this comment.
Shouldn't this contain a bunch of parentheses, to ensure && and || are evaluated in the correct order?
It always binds tightest in the order: >=, &&, ||. I'm going to add the parentheses anyway.
What's the L needed for? I don't think it's essential.
Good to know.
There was a problem hiding this comment.
I'm going to add the parentheses anyway.
Thank you :) I can never remember the order, and GCC sometimes warns about "|| within &&" and such if I forget the braces, so I suspect it's always different that I would expect :D
There was a problem hiding this comment.
This table always helps: https://en.cppreference.com/w/cpp/language/operator_precedence.
There was a problem hiding this comment.
Wait so the second MSVC-specific part is no longer needed? I don't see it in the last revision.
There was a problem hiding this comment.
Good catch! It was only in the Magnum PR.
There was a problem hiding this comment.
This is still missing the parentheses...
| @@ -394,12 +394,19 @@ Expands to @cpp constexpr @ce on C++14 and newer, empty on C++11. Useful for | |||
| selectively marking functions that make use of C++14 relaxed constexpr rules. | |||
There was a problem hiding this comment.
Since the macro is quite a bit more complex now, I'm thinking a test could be a good idea -- there's src/Corrade/Utility/MacrosCppXYTest.cpp which currently test C++17 and 20 features, so a new MacrosCpp14Test.cpp (built only on C++14-capable compilers) would contain a test for this macro:
...
CORRADE_CONSTEXPR14 int sumInAStupidWay(int number) {
int sum = 0;
for(int i = 0; i != number; ++i)
sum += i;
return sum;
}
void MacrosCpp14Test::constexpr14() {
#ifndef CORRADE_CONSTEXPR14 // errr, test if it's actually non-empty, in some way
CORRADE_SKIP("CORRADE_CONSTEXPR14 not available on this compiler.");
#else
constexpr int sum = sumInAStupidWay(17);
CORRADE_COMPARE(sum, 153);
#endif
}
}}}}
CORRADE_TEST_MAIN(Corrade::Utility::Test::MacrosCpp14Test)Because without the test it's hard to verify that the macro is actually correctly defined only where C++14 constexpr works.
And the docs should be extended to mention the compiler versions on which the macro is defined.
Oh, and similar test for the other macro, there's already a MacrosCpp20Test.cpp so just add a new case there.
There was a problem hiding this comment.
Generally when testing constexpr functions I recommend putting the compiler in a situation where it can't weasel out of performing the computation at compile-time. Hence the static assert.
There was a problem hiding this comment.
Ah yes, good idea. Except that now you're using the C++17 variant of it ;)
There was a problem hiding this comment.
I think I managed to test whether the function is constexpr through SFINAE.
There was a problem hiding this comment.
Still needs the documentation update...
9f1acfa to
ba036e1
Compare
| MacrosCpp14Test::MacrosCpp14Test() { | ||
| addTests({&MacrosCpp14Test::constexpr14}); | ||
| } |
There was a problem hiding this comment.
Can you follow the same method order as in other tests? Constructor first, helper functions defined next to where they get used, etc.
| template<int> struct sfinae : std::true_type{}; | ||
| template<class T> sfinae<(T::sumInAStupidWay(0), 0)> check(int); | ||
| template<class> std::false_type check(...); | ||
| template<class T> struct hasRelaxedConstexpr : decltype(check<T>(0)){}; |
There was a problem hiding this comment.
But this way you're not testing if the macro is actually defined to constexpr when it should be, no? Like, the test would pass even if CORRADE_CONSTEXPR14 would be empty always, or if you wouldn't use it at all.
... and you're not using the static assert anymore :P
There really needs to be something based on whether the macro is empty or not.
There was a problem hiding this comment.
Alright, so I added an #if 0 so that it can be verified. Sadly static assert broke the build.
There was a problem hiding this comment.
I don't like this solution, to be honest. Because it requires manual fiddling with the #if 0, it's impossible to test on the CI, and thus it's the same as if the whole test file wouldn't be here.
There was a problem hiding this comment.
What then, you want the test to fail rather than skip?
There was a problem hiding this comment.
The test would pass even if CORRADE_CONSTEXPR14 wasn't used anywhere in it, that's the problem I have with it. It's not testing the thing it should be testing, so it's useless.
There was a problem hiding this comment.
It'll skip on an old compiler, that's why that sfinae logic is there in the first place. Toggle the #if 0 and see.
302d124 to
6d68526
Compare
|
Actually, I'm still not sure what is the main reason the change to Apart from MSVC, are there any relevant compilers that report C++14 as supported via the Then, for MSVC, isn't it just about excluding MSVC 2015? It would boil down to #if CORRADE_CXX_STANDARD >= 201402 && !defined(CORRADE_MSVC2015_COMPATIBILITY)
#define CORRADE_CONSTEXPR14 constexpr
...
#endifand using void MacrosCpp14Test::constexpr14() {
#ifdef CORRADE_MSVC2015_COMPATIBILITY
CORRADE_SKIP("CORRADE_CONSTEXPR14 not available on MSVC2015.");
#else
constexpr int sum = sumInAStupidWay(17);
CORRADE_COMPARE(sum, 153);
#endif
}[Sorry for the accidental close, pressed too many buttons at once.] |
Compilers tend to expose https://gcc.gnu.org/projects/cxx-status.html -- 4.3 -> 5.0*
The whole point is to handle that for cases such as Magnum vector code. Or am I meant to litter it with |
Yes, I'm not trying to solve the general case of "is feature X supported completely and without bugs on compiler Y", here it's just about having the simplest possible condition for "is C++14 constexpr supported on compilers we care about", and since C++14 is rather old and the relevant compilers are dying out, it can be coarser than, say, checking for
What? Why? The whole point here is to define the macro in a way that does the right thing without a need for extra checks every time it's used, and have a test that verifies it indeed does the right thing. I guess easiest is if I just do the thing instead of talking about it. The |
| #if (defined(__clang__) && __clang_major__ >= 9) || (defined(__GNUG__) && __GNUG__ >= 9) || (defined(_MSC_VER) && _MSC_VER >= 1931) | ||
| #define CORRADE_CONSTEVAL (__builtin_is_constant_evaluated()) | ||
| #elif CORRADE_CXX_STANDARD >= 202002 | ||
| #define CORRADE_CONSTEVAL (std::is_constant_evaluated()) |
There was a problem hiding this comment.
Since this depends on <type_traits>, I'm thinking the macro should go to TypeTraits.h instead. The Macros.h header deliberately doesn't pull in any STL headers.
| extension. In which case it may be used under C++14 relaxed constexpr rules. | ||
| */ | ||
| #if (defined(__clang__) && __clang_major__ >= 9) || (defined(__GNUG__) && __GNUG__ >= 9) || (defined(_MSC_VER) && _MSC_VER >= 1931) | ||
| #define CORRADE_CONSTEVAL (__builtin_is_constant_evaluated()) |
There was a problem hiding this comment.
I'm thinking CORRADE_IS_CONSTANT_EVALUATED would be a less confusing name.
| This support is available on all C++20 capable compilers, but also certain | ||
| ones (Clang 9, GCC 9, MSVC 17.1) that expose the feature as a non-portable | ||
| extension. In which case it may be used under C++14 relaxed constexpr rules. | ||
| */ |
There was a problem hiding this comment.
Thanks for the docs, now it's just a test missing :) TypeTraitsCpp20Test.cpp
c95cbd4 to
e6c22d0
Compare
|
Note, it's specifically not meant to be used as |
This is useful for future SIMD support in Magnum vectors. v2: Add test.
e6c22d0 to
a0a1601
Compare
This is going to be used in Magnum vectors.