diff options
| author | Leitwolf11 | 2026-10-23 02:33:21 +0300 |
|---|---|---|
| committer | Leitwolf11 | 2026-10-23 02:33:21 +0300 |
| commit | c7e625419e699f139c15ae190b0169d93768abe7 (patch) | |
| tree | f39027814c87061e8f3ff9cc269945e1219372e2 /src | |
| parent | afac14ac5a62d8d2e7efd2184ad34e16593eddfd (diff) | |
| download | catch3-c7e625419e699f139c15ae190b0169d93768abe7.tar.gz | |
Draw tuples without capturing a pack in a nested lambda
MSVC rejected Gen::Tuples with C3493: the strategies were captured as
a parameter pack and used inside a nested std::apply lambda. The
strategies are now held as one std::tuple and drawn by
Detail::DrawTuple over an index sequence; the comma fold still draws
them strictly left to right, so choice sequences do not change.
Verified: ProgmasoftSelfTest passes with MSVC 19.51 (cl) and with
clang-cl 23, 57 test cases and 75,461 assertions each. The macOS and
CodeQL failures of the previous run were runners that never started.
Diffstat (limited to 'src')
| -rw-r--r-- | src/Progmasoft/Catch3/Strategy/Containers.hpp | 56 |
1 files changed, 32 insertions, 24 deletions
diff --git a/src/Progmasoft/Catch3/Strategy/Containers.hpp b/src/Progmasoft/Catch3/Strategy/Containers.hpp index 477df896..ad4daf39 100644 --- a/src/Progmasoft/Catch3/Strategy/Containers.hpp +++ b/src/Progmasoft/Catch3/Strategy/Containers.hpp @@ -61,6 +61,30 @@ namespace Progmasoft::Catch3 return true; } + /// Draws one value from each strategy, strictly left to right: the + /// fold over the comma operator fixes the order, which keeps the + /// choice sequence of a tuple stable. + template<typename... ValueTypes, std::size_t... Index> + [[nodiscard]] std::optional<std::tuple<ValueTypes...>> + DrawTuple(const std::tuple<Strategy<ValueTypes>...> &strategies, + ChoiceSource &source, + std::index_sequence<Index...>) + { + std::tuple<std::optional<ValueTypes>...> parts; + bool complete = true; + ((complete = complete + && (std::get<Index>(parts) + = std::get<Index>(strategies).Draw(source)) + .has_value()), + ...); + if (!complete) + { + return std::nullopt; + } + return std::tuple<ValueTypes...>( + std::move(*std::get<Index>(parts))...); + } + inline void CheckRange(const SizeRange &range) { @@ -320,31 +344,15 @@ namespace Progmasoft::Catch3 [[nodiscard]] Strategy<std::tuple<ValueTypes...>> Tuples(Strategy<ValueTypes>... strategies) { + // The strategies are held as one tuple rather than captured as + // a pack: MSVC rejects a pack used inside a nested lambda. return Strategy<std::tuple<ValueTypes...>>( - [strategies...](ChoiceSource &source) - -> std::optional<std::tuple<ValueTypes...>> { - std::tuple<std::optional<ValueTypes>...> parts; - bool complete = true; - // A braced list fixes the evaluation order: left to - // right, which keeps the choice sequence stable. - std::apply( - [&](auto &...part) { - ((complete = complete - && (part = strategies.Draw(source)) - .has_value()), - ...); - }, - parts); - if (!complete) - { - return std::nullopt; - } - return std::apply( - [](auto &...part) { - return std::tuple<ValueTypes...>( - std::move(*part)...); - }, - parts); + [strategies = std::tuple<Strategy<ValueTypes>...>( + std::move(strategies)...)](ChoiceSource &source) { + return Detail::DrawTuple( + strategies, + source, + std::index_sequence_for<ValueTypes...>{}); }); } |