Add enum types to what is captured by value by default

As it turns out, enums can be used to declare bitfields, and we
cannot form a reference to a bitfield in the cpature. Thus, we add
`std::is_enum` as a criteria to the default for `capture_by_value`,
so that enum-based bitfields are also captured by value and thus
decomposable.

Closes #3001
This commit is contained in:
Martin Hořeňovský
2025-07-29 23:51:13 +02:00
parent a1c7ee115f
commit ccabd4de89
20 changed files with 164 additions and 29 deletions

View File

@@ -78,10 +78,11 @@
*
* 3) If a type has no linkage, we also cannot capture it by reference.
* The solution is once again to capture them by value. We handle
* the common cases by using `std::is_arithmetic` as the default
* for `Catch::capture_by_value`, but that is only a some-effort
* heuristic. But as with 2), users can specialize `capture_by_value`
* for their own types as needed.
* the common cases by using `std::is_arithmetic` and `std::is_enum`
* as the default for `Catch::capture_by_value`, but that is only a
* some-effort heuristic. These combine to capture all possible bitfield
* bases, and also some trait-like types. As with 2), users can
* specialize `capture_by_value` for their own types as needed.
*
* 4) To support C++20 and make the SFINAE on our decomposing operators
* work, the SFINAE has to happen in return type, rather than in
@@ -133,13 +134,22 @@ namespace Catch {
using RemoveCVRef_t = std::remove_cv_t<std::remove_reference_t<T>>;
}
// Note: There is nothing that stops us from extending this,
// e.g. to `std::is_scalar`, but the more encompassing
// traits are usually also more expensive. For now we
// keep this as it used to be and it can be changed later.
// Note: This is about as much as we can currently reasonably support.
// In an ideal world, we could capture by value small trivially
// copyable types, but the actual `std::is_trivially_copyable`
// trait is a huge mess with standard-violating results on
// GCC and Clang, which are unlikely to be fixed soon due to ABI
// concerns.
// `std::is_scalar` also causes issues due to the `is_pointer`
// component, which causes ambiguity issues with (references-to)
// function pointer. If those are resolved, we still need to
// disambiguate the overload set for arrays, through explicit
// overload for references to sized arrays.
template <typename T>
struct capture_by_value
: std::integral_constant<bool, std::is_arithmetic<T>{}> {};
: std::integral_constant<bool,
std::is_arithmetic<T>::value ||
std::is_enum<T>::value> {};
#if defined( CATCH_CONFIG_CPP20_COMPARE_OVERLOADS )
template <>