diff --git a/docs/reference/testing.md b/docs/reference/testing.md
index ea43721e..ae8a079f 100644
--- a/docs/reference/testing.md
+++ b/docs/reference/testing.md
@@ -103,14 +103,15 @@ namespace:
-| Parameter Generator | Behavior |
-| ------------------- | ---------------------------------------------------- |
-| `Range(begin, end [, step])` | Yields values `{begin, begin+step, begin+step+step, ...}`. The values do not include `end`. `step` defaults to 1. |
-| `Values(v1, v2, ..., vN)` | Yields values `{v1, v2, ..., vN}`. |
-| `ValuesIn(container)` or `ValuesIn(begin,end)` | Yields values from a C-style array, an STL-style container, or an iterator range `[begin, end)`. |
-| `Bool()` | Yields sequence `{false, true}`. |
-| `Combine(g1, g2, ..., gN)` | Yields as `std::tuple` *n*-tuples all combinations (Cartesian product) of the values generated by the given *n* generators `g1`, `g2`, ..., `gN`. |
-| `ConvertGenerator(g)` or `ConvertGenerator(g, func)` | Yields values generated by generator `g`, `static_cast` from `T`. (Note: `T` might not be what you expect. See [*Using ConvertGenerator*](#using-convertgenerator) below.) The second overload uses `func` to perform the conversion. |
+| Parameter Generator | Behavior |
+|---------------------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
+| `Range(begin, end [, step])` | Yields values `{begin, begin+step, begin+step+step, ...}`. The values do not include `end`. `step` defaults to 1. |
+| `Values(v1, v2, ..., vN)` | Yields values `{v1, v2, ..., vN}`. |
+| `ValuesIn(container)` or `ValuesIn(begin,end)` | Yields values from a C-style array, an STL-style container, or an iterator range `[begin, end)`. |
+| `Bool()` | Yields sequence `{false, true}`. |
+| `Combine(g1, g2, ..., gN)` | Yields as `std::tuple` *n*-tuples all combinations (Cartesian product) of the values generated by the given *n* generators `g1`, `g2`, ..., `gN`. |
+| `CombineAs(g1, g2, ..., gN)` | Yields as `R` *n*-instances all combinations (Cartesian product) of the values generated by the given *n* generators `g1`, `g2`, ..., `gN`. |
+| `ConvertGenerator(g)` or `ConvertGenerator(g, func)` | Yields values generated by generator `g`, `static_cast` from `T`. (Note: `T` might not be what you expect. See [*Using ConvertGenerator*](#using-convertgenerator) below.) The second overload uses `func` to perform the conversion. |
The optional last argument *`name_generator`* is a function or functor that
generates custom test name suffixes based on the test parameters. The function
@@ -234,6 +235,24 @@ To overcome this problem you can specify the generated type explicitly:
dangling reference because the type deduction strips off the reference and the
`const`).
+###### Using `CombineAs`
+
+If you think the code above is too complicated, and you do not want to deal
+with tuples, you may want to use `CombineAs()` which works like a combination
+of `Combine()` + `ConvertGenerator()` + tuple unpacking function.
+
+```cpp
+// The fixture's parameter type.
+class MyParam {
+ public:
+ MyParam(int, bool);
+ ...
+};
+
+INSTANTIATE_TEST_SUITE_P(MyInstantiation, MyTestSuite,
+ CombineAs(Values(1, 1.2), Bool()));
+```
+
### TYPED_TEST_SUITE {#TYPED_TEST_SUITE}
`TYPED_TEST_SUITE(`*`TestFixtureName`*`,`*`Types`*`)`
diff --git a/docs/samples.md b/docs/samples.md
index dedc5909..e75323e1 100644
--- a/docs/samples.md
+++ b/docs/samples.md
@@ -15,7 +15,7 @@ variety of googletest features.
derived fixtures.
* Sample #6 demonstrates type-parameterized tests.
* Sample #7 teaches the basics of value-parameterized tests.
-* Sample #8 shows using `Combine()` in value-parameterized tests.
+* Sample #8 shows using `Combine()` and `CombineAs()` in value-parameterized tests.
* Sample #9 shows use of the listener API to modify Google Test's console
output and the use of its reflection API to inspect test results.
* Sample #10 shows use of the listener API to implement a primitive memory
diff --git a/googletest/include/gtest/gtest.h b/googletest/include/gtest/gtest.h
index 69994ee9..8beb45f5 100644
--- a/googletest/include/gtest/gtest.h
+++ b/googletest/include/gtest/gtest.h
@@ -61,15 +61,15 @@
#include
#include "gtest/gtest-assertion-result.h" // IWYU pragma: export
-#include "gtest/gtest-death-test.h" // IWYU pragma: export
-#include "gtest/gtest-matchers.h" // IWYU pragma: export
-#include "gtest/gtest-message.h" // IWYU pragma: export
-#include "gtest/gtest-param-test.h" // IWYU pragma: export
-#include "gtest/gtest-printers.h" // IWYU pragma: export
-#include "gtest/gtest-test-part.h" // IWYU pragma: export
-#include "gtest/gtest-typed-test.h" // IWYU pragma: export
-#include "gtest/gtest_pred_impl.h" // IWYU pragma: export
-#include "gtest/gtest_prod.h" // IWYU pragma: export
+#include "gtest/gtest-death-test.h" // IWYU pragma: export
+#include "gtest/gtest-matchers.h" // IWYU pragma: export
+#include "gtest/gtest-message.h" // IWYU pragma: export
+#include "gtest/gtest-param-test.h" // IWYU pragma: export
+#include "gtest/gtest-printers.h" // IWYU pragma: export
+#include "gtest/gtest-test-part.h" // IWYU pragma: export
+#include "gtest/gtest-typed-test.h" // IWYU pragma: export
+#include "gtest/gtest_pred_impl.h" // IWYU pragma: export
+#include "gtest/gtest_prod.h" // IWYU pragma: export
#include "gtest/internal/gtest-internal.h"
#include "gtest/internal/gtest-string.h"
@@ -1664,7 +1664,8 @@ class GTEST_API_ AssertHelper {
// the GetParam() method.
//
// Use it with one of the parameter generator defining functions, like Range(),
-// Values(), ValuesIn(), Bool(), Combine(), and ConvertGenerator().
+// Values(), ValuesIn(), Bool(), Combine(), CombineAs(), and
+// ConvertGenerator().
//
// class FooTest : public ::testing::TestWithParam {
// protected:
diff --git a/googletest/samples/sample8_unittest.cc b/googletest/samples/sample8_unittest.cc
index 4df81df0..009338b0 100644
--- a/googletest/samples/sample8_unittest.cc
+++ b/googletest/samples/sample8_unittest.cc
@@ -81,6 +81,7 @@ class HybridPrimeTable : public PrimeTable {
using ::testing::Bool;
using ::testing::Combine;
+using ::testing::CombineAs;
using ::testing::TestWithParam;
using ::testing::Values;
@@ -151,4 +152,45 @@ TEST_P(PrimeTableTest, CanGetNextPrime) {
INSTANTIATE_TEST_SUITE_P(MeaningfulTestParameters, PrimeTableTest,
Combine(Bool(), Values(1, 10)));
+// But now you look at the PrimeTableTest and you think dealing with std::tuple
+// requires some boilerplate to unwrap it. You can use combined parameters of
+// custom types easily with help of CombineAs().
+struct WellTypedPrimeTableTestParams {
+ bool force_on_the_fly;
+ int max_precalculated;
+};
+
+class WellTypedPrimeTableTest
+ : public TestWithParam {
+ protected:
+ void SetUp() override {
+ // It is possible to avoid destructuring of the std::tuple if we use struct
+ // as the test parameter type.
+ table_ = new HybridPrimeTable(GetParam().force_on_the_fly,
+ GetParam().max_precalculated);
+ }
+ void TearDown() override {
+ delete table_;
+ table_ = nullptr;
+ }
+ HybridPrimeTable* table_ = nullptr;
+};
+
+// The tests are made the same way as above
+TEST_P(WellTypedPrimeTableTest, CanGetNextPrime) {
+ EXPECT_EQ(2, table_->GetNextPrime(0));
+ EXPECT_EQ(3, table_->GetNextPrime(2));
+ EXPECT_EQ(5, table_->GetNextPrime(3));
+ EXPECT_EQ(7, table_->GetNextPrime(5));
+ EXPECT_EQ(11, table_->GetNextPrime(7));
+ EXPECT_EQ(131, table_->GetNextPrime(128));
+}
+
+// Here we instantiate our tests with combined parameters and straightforward
+// typing. CombineAs() allows you to generate all possible combinations of
+// values the same way as Combine() does, but also converts them to the desired
+// type.
+INSTANTIATE_TEST_SUITE_P(MeaningfulTestParameters, WellTypedPrimeTableTest,
+ CombineAs(Bool(), Values(1, 10)));
+
} // namespace