-
Notifications
You must be signed in to change notification settings - Fork 1.6k
Description
We have a long-standing convention of commenting all preprocessor directives. This is extremely useful when preprocessor-controlled code is large and/or nested, because the comments clearly identify region boundaries. (This is even more important now that clang-format indents all preprocessor directives at 0.) Here's an example with large regions:
Lines 1228 to 1250 in 1d39dfa
| #if _HAS_STATIC_RTTI | |
| _NODISCARD const type_info& target_type() const noexcept { | |
| return this->_Target_type(); | |
| } | |
| template <class _Fx> | |
| _NODISCARD _Fx* target() noexcept { | |
| return reinterpret_cast<_Fx*>(const_cast<void*>(this->_Target(typeid(_Fx)))); | |
| } | |
| template <class _Fx> | |
| _NODISCARD const _Fx* target() const noexcept { | |
| return reinterpret_cast<const _Fx*>(this->_Target(typeid(_Fx))); | |
| } | |
| #else // _HAS_STATIC_RTTI | |
| const type_info& target_type() const noexcept = delete; // requires static RTTI | |
| template <class _Fx> | |
| _Fx* target() noexcept = delete; // requires static RTTI | |
| template <class _Fx> | |
| const _Fx* target() const noexcept = delete; // requires static RTTI | |
| #endif // _HAS_STATIC_RTTI |
And nested regions:
Lines 295 to 306 in 1d39dfa
| #if _HAS_CXX17 | |
| #if _HAS_U8_INTRINSICS | |
| if constexpr (is_same_v<_Elem, char8_t>) { | |
| return __builtin_u8memcmp(_First1, _First2, _Count); | |
| } else | |
| #endif // _HAS_U8_INTRINSICS | |
| { | |
| return __builtin_memcmp(_First1, _First2, _Count); | |
| } | |
| #else // _HAS_CXX17 | |
| return _CSTD memcmp(_First1, _First2, _Count); | |
| #endif // _HAS_CXX17 |
But when preprocessor-controlled code is small (down to a single line) and non-nested, it starts looking silly, as @SuperWig observed in #340 (comment) :
Lines 866 to 870 in 1d39dfa
| #if _HAS_STATIC_RTTI | |
| return typeid(_Callable); | |
| #else // _HAS_STATIC_RTTI | |
| return typeid(void); | |
| #endif // _HAS_STATIC_RTTI |
In newer code, we sometimes use "arrow comments" to make regions even more visible, which is an improvement for large and/or nested scenarios as usual:
Lines 259 to 284 in 1d39dfa
| #if _HAS_CONDITIONAL_EXPLICIT | |
| template <class _This2 = _This, | |
| enable_if_t<conjunction_v<is_default_constructible<_This2>, is_default_constructible<_Rest>...>, int> = 0> | |
| constexpr explicit( | |
| !conjunction_v<_Is_implicitly_default_constructible<_This2>, _Is_implicitly_default_constructible<_Rest>...>) | |
| tuple() noexcept(conjunction_v<is_nothrow_default_constructible<_This2>, | |
| is_nothrow_default_constructible<_Rest>...>) // strengthened | |
| : _Mybase(), _Myfirst() {} | |
| #else // ^^^ _HAS_CONDITIONAL_EXPLICIT ^^^ / vvv !_HAS_CONDITIONAL_EXPLICIT vvv | |
| template <class _This2 = _This, | |
| enable_if_t<conjunction_v<is_default_constructible<_This2>, is_default_constructible<_Rest>..., | |
| _Is_implicitly_default_constructible<_This2>, _Is_implicitly_default_constructible<_Rest>...>, | |
| int> = 0> | |
| constexpr tuple() noexcept(conjunction_v<is_nothrow_default_constructible<_This2>, | |
| is_nothrow_default_constructible<_Rest>...>) // strengthened | |
| : _Mybase(), _Myfirst() {} | |
| template <class _This2 = _This, | |
| enable_if_t<conjunction_v<is_default_constructible<_This2>, is_default_constructible<_Rest>..., | |
| negation<conjunction<_Is_implicitly_default_constructible<_This2>, | |
| _Is_implicitly_default_constructible<_Rest>...>>>, | |
| int> = 0> | |
| constexpr explicit tuple() noexcept(conjunction_v<is_nothrow_default_constructible<_This2>, | |
| is_nothrow_default_constructible<_Rest>...>) // strengthened | |
| : _Mybase(), _Myfirst() {} | |
| #endif // ^^^ !_HAS_CONDITIONAL_EXPLICIT ^^^ |
But similarly, it is generally silly for small non-nested scenarios (at least with simple conditions; the comments can be useful for complicated conditions even if the controlled code is small):
Lines 691 to 695 in 1d39dfa
| #if _HAS_CXX17 | |
| return _Result; | |
| #else // ^^^ _HAS_CXX17 ^^^ // vvv !_HAS_CXX17 vvv | |
| (void) _Result; | |
| #endif // _HAS_CXX17 |
We should consider developing a simple set of rules for contributors to follow. Example suggestion:
- All
#elseand#endifdirectives should have arrow comments, - Except when the condition is simple, all of the controlled regions are a single line, and there is no nearby nesting.
That would require a bit of human judgement (what is "simple", what is "nearby"), but not very much.