Googletest export
Add ::testing::FieldsAre matcher for objects that support get<> and structured bindings. PiperOrigin-RevId: 337165285
This commit is contained in:
parent
f3dbe3ec44
commit
a462188865
@ -403,6 +403,7 @@ messages, you can use:
|
|||||||
| `Field(&class::field, m)` | `argument.field` (or `argument->field` when `argument` is a plain pointer) matches matcher `m`, where `argument` is an object of type _class_. |
|
| `Field(&class::field, m)` | `argument.field` (or `argument->field` when `argument` is a plain pointer) matches matcher `m`, where `argument` is an object of type _class_. |
|
||||||
| `Key(e)` | `argument.first` matches `e`, which can be either a value or a matcher. E.g. `Contains(Key(Le(5)))` can verify that a `map` contains a key `<= 5`. |
|
| `Key(e)` | `argument.first` matches `e`, which can be either a value or a matcher. E.g. `Contains(Key(Le(5)))` can verify that a `map` contains a key `<= 5`. |
|
||||||
| `Pair(m1, m2)` | `argument` is an `std::pair` whose `first` field matches `m1` and `second` field matches `m2`. |
|
| `Pair(m1, m2)` | `argument` is an `std::pair` whose `first` field matches `m1` and `second` field matches `m2`. |
|
||||||
|
| `FieldsAre(m...)` | `argument` is a compatible object where each field matches piecewise with `m...`. A compatible object is any that supports the `std::tuple_size<Obj>`+`get<I>(obj)` protocol. In C++17 and up this also supports types compatible with structured bindings, like aggregates. |
|
||||||
| `Property(&class::property, m)` | `argument.property()` (or `argument->property()` when `argument` is a plain pointer) matches matcher `m`, where `argument` is an object of type _class_. |
|
| `Property(&class::property, m)` | `argument.property()` (or `argument->property()` when `argument` is a plain pointer) matches matcher `m`, where `argument` is an object of type _class_. |
|
||||||
<!-- mdformat on -->
|
<!-- mdformat on -->
|
||||||
|
|
||||||
|
@ -2879,6 +2879,203 @@ class PairMatcher {
|
|||||||
const SecondMatcher second_matcher_;
|
const SecondMatcher second_matcher_;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template <typename T, size_t... I>
|
||||||
|
auto UnpackStructImpl(const T& t, IndexSequence<I...>, int)
|
||||||
|
-> decltype(std::tie(get<I>(t)...)) {
|
||||||
|
static_assert(std::tuple_size<T>::value == sizeof...(I),
|
||||||
|
"Number of arguments doesn't match the number of fields.");
|
||||||
|
return std::tie(get<I>(t)...);
|
||||||
|
}
|
||||||
|
|
||||||
|
#if defined(__cpp_structured_bindings) && __cpp_structured_bindings >= 201606
|
||||||
|
template <typename T>
|
||||||
|
auto UnpackStructImpl(const T& t, MakeIndexSequence<1>, char) {
|
||||||
|
const auto& [a] = t;
|
||||||
|
return std::tie(a);
|
||||||
|
}
|
||||||
|
template <typename T>
|
||||||
|
auto UnpackStructImpl(const T& t, MakeIndexSequence<2>, char) {
|
||||||
|
const auto& [a, b] = t;
|
||||||
|
return std::tie(a, b);
|
||||||
|
}
|
||||||
|
template <typename T>
|
||||||
|
auto UnpackStructImpl(const T& t, MakeIndexSequence<3>, char) {
|
||||||
|
const auto& [a, b, c] = t;
|
||||||
|
return std::tie(a, b, c);
|
||||||
|
}
|
||||||
|
template <typename T>
|
||||||
|
auto UnpackStructImpl(const T& t, MakeIndexSequence<4>, char) {
|
||||||
|
const auto& [a, b, c, d] = t;
|
||||||
|
return std::tie(a, b, c, d);
|
||||||
|
}
|
||||||
|
template <typename T>
|
||||||
|
auto UnpackStructImpl(const T& t, MakeIndexSequence<5>, char) {
|
||||||
|
const auto& [a, b, c, d, e] = t;
|
||||||
|
return std::tie(a, b, c, d, e);
|
||||||
|
}
|
||||||
|
template <typename T>
|
||||||
|
auto UnpackStructImpl(const T& t, MakeIndexSequence<6>, char) {
|
||||||
|
const auto& [a, b, c, d, e, f] = t;
|
||||||
|
return std::tie(a, b, c, d, e, f);
|
||||||
|
}
|
||||||
|
template <typename T>
|
||||||
|
auto UnpackStructImpl(const T& t, MakeIndexSequence<7>, char) {
|
||||||
|
const auto& [a, b, c, d, e, f, g] = t;
|
||||||
|
return std::tie(a, b, c, d, e, f, g);
|
||||||
|
}
|
||||||
|
template <typename T>
|
||||||
|
auto UnpackStructImpl(const T& t, MakeIndexSequence<8>, char) {
|
||||||
|
const auto& [a, b, c, d, e, f, g, h] = t;
|
||||||
|
return std::tie(a, b, c, d, e, f, g, h);
|
||||||
|
}
|
||||||
|
template <typename T>
|
||||||
|
auto UnpackStructImpl(const T& t, MakeIndexSequence<9>, char) {
|
||||||
|
const auto& [a, b, c, d, e, f, g, h, i] = t;
|
||||||
|
return std::tie(a, b, c, d, e, f, g, h, i);
|
||||||
|
}
|
||||||
|
template <typename T>
|
||||||
|
auto UnpackStructImpl(const T& t, MakeIndexSequence<10>, char) {
|
||||||
|
const auto& [a, b, c, d, e, f, g, h, i, j] = t;
|
||||||
|
return std::tie(a, b, c, d, e, f, g, h, i, j);
|
||||||
|
}
|
||||||
|
template <typename T>
|
||||||
|
auto UnpackStructImpl(const T& t, MakeIndexSequence<11>, char) {
|
||||||
|
const auto& [a, b, c, d, e, f, g, h, i, j, k] = t;
|
||||||
|
return std::tie(a, b, c, d, e, f, g, h, i, j, k);
|
||||||
|
}
|
||||||
|
template <typename T>
|
||||||
|
auto UnpackStructImpl(const T& t, MakeIndexSequence<12>, char) {
|
||||||
|
const auto& [a, b, c, d, e, f, g, h, i, j, k, l] = t;
|
||||||
|
return std::tie(a, b, c, d, e, f, g, h, i, j, k, l);
|
||||||
|
}
|
||||||
|
template <typename T>
|
||||||
|
auto UnpackStructImpl(const T& t, MakeIndexSequence<13>, char) {
|
||||||
|
const auto& [a, b, c, d, e, f, g, h, i, j, k, l, m] = t;
|
||||||
|
return std::tie(a, b, c, d, e, f, g, h, i, j, k, l, m);
|
||||||
|
}
|
||||||
|
template <typename T>
|
||||||
|
auto UnpackStructImpl(const T& t, MakeIndexSequence<14>, char) {
|
||||||
|
const auto& [a, b, c, d, e, f, g, h, i, j, k, l, m, n] = t;
|
||||||
|
return std::tie(a, b, c, d, e, f, g, h, i, j, k, l, m, n);
|
||||||
|
}
|
||||||
|
template <typename T>
|
||||||
|
auto UnpackStructImpl(const T& t, MakeIndexSequence<15>, char) {
|
||||||
|
const auto& [a, b, c, d, e, f, g, h, i, j, k, l, m, n, o] = t;
|
||||||
|
return std::tie(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o);
|
||||||
|
}
|
||||||
|
template <typename T>
|
||||||
|
auto UnpackStructImpl(const T& t, MakeIndexSequence<16>, char) {
|
||||||
|
const auto& [a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p] = t;
|
||||||
|
return std::tie(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p);
|
||||||
|
}
|
||||||
|
#endif // defined(__cpp_structured_bindings)
|
||||||
|
|
||||||
|
template <size_t I, typename T>
|
||||||
|
auto UnpackStruct(const T& t)
|
||||||
|
-> decltype((UnpackStructImpl)(t, MakeIndexSequence<I>{}, 0)) {
|
||||||
|
return (UnpackStructImpl)(t, MakeIndexSequence<I>{}, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Helper function to do comma folding in C++11.
|
||||||
|
// The array ensures left-to-right order of evaluation.
|
||||||
|
// Usage: VariadicExpand({expr...});
|
||||||
|
template <typename T, size_t N>
|
||||||
|
void VariadicExpand(const T (&a)[N]) {}
|
||||||
|
|
||||||
|
template <typename Struct, typename StructSize>
|
||||||
|
class FieldsAreMatcherImpl;
|
||||||
|
|
||||||
|
template <typename Struct, size_t... I>
|
||||||
|
class FieldsAreMatcherImpl<Struct, IndexSequence<I...>>
|
||||||
|
: public MatcherInterface<Struct> {
|
||||||
|
using UnpackedType =
|
||||||
|
decltype(UnpackStruct<sizeof...(I)>(std::declval<const Struct&>()));
|
||||||
|
using MatchersType = std::tuple<
|
||||||
|
Matcher<const typename std::tuple_element<I, UnpackedType>::type&>...>;
|
||||||
|
|
||||||
|
public:
|
||||||
|
template <typename Inner>
|
||||||
|
explicit FieldsAreMatcherImpl(const Inner& matchers)
|
||||||
|
: matchers_(testing::SafeMatcherCast<
|
||||||
|
const typename std::tuple_element<I, UnpackedType>::type&>(
|
||||||
|
std::get<I>(matchers))...) {}
|
||||||
|
|
||||||
|
void DescribeTo(::std::ostream* os) const override {
|
||||||
|
const char* separator = "";
|
||||||
|
VariadicExpand(
|
||||||
|
{(*os << separator << "has field #" << I << " that ",
|
||||||
|
std::get<I>(matchers_).DescribeTo(os), separator = ", and ")...});
|
||||||
|
}
|
||||||
|
|
||||||
|
void DescribeNegationTo(::std::ostream* os) const override {
|
||||||
|
const char* separator = "";
|
||||||
|
VariadicExpand({(*os << separator << "has field #" << I << " that ",
|
||||||
|
std::get<I>(matchers_).DescribeNegationTo(os),
|
||||||
|
separator = ", or ")...});
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MatchAndExplain(Struct t, MatchResultListener* listener) const override {
|
||||||
|
return MatchInternal((UnpackStruct<sizeof...(I)>)(t), listener);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool MatchInternal(UnpackedType tuple, MatchResultListener* listener) const {
|
||||||
|
if (!listener->IsInterested()) {
|
||||||
|
// If the listener is not interested, we don't need to construct the
|
||||||
|
// explanation.
|
||||||
|
bool good = true;
|
||||||
|
VariadicExpand({good = good && std::get<I>(matchers_).Matches(
|
||||||
|
std::get<I>(tuple))...});
|
||||||
|
return good;
|
||||||
|
}
|
||||||
|
|
||||||
|
int failed_pos = -1;
|
||||||
|
|
||||||
|
std::vector<StringMatchResultListener> inner_listener(sizeof...(I));
|
||||||
|
|
||||||
|
VariadicExpand(
|
||||||
|
{failed_pos == -1 && !std::get<I>(matchers_).MatchAndExplain(
|
||||||
|
std::get<I>(tuple), &inner_listener[I])
|
||||||
|
? failed_pos = I
|
||||||
|
: 0 ...});
|
||||||
|
if (failed_pos != ~size_t{}) {
|
||||||
|
*listener << "whose field #" << failed_pos << " does not match";
|
||||||
|
PrintIfNotEmpty(inner_listener[failed_pos].str(), listener->stream());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
*listener << "whose all elements match";
|
||||||
|
const char* separator = ", where";
|
||||||
|
for (size_t index = 0; index < sizeof...(I); ++index) {
|
||||||
|
const std::string str = inner_listener[index].str();
|
||||||
|
if (!str.empty()) {
|
||||||
|
*listener << separator << " field #" << index << " is a value " << str;
|
||||||
|
separator = ", and";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
MatchersType matchers_;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename... Inner>
|
||||||
|
class FieldsAreMatcher {
|
||||||
|
public:
|
||||||
|
explicit FieldsAreMatcher(Inner... inner) : matchers_(std::move(inner)...) {}
|
||||||
|
|
||||||
|
template <typename Struct>
|
||||||
|
operator Matcher<Struct>() const { // NOLINT
|
||||||
|
return Matcher<Struct>(
|
||||||
|
new FieldsAreMatcherImpl<const Struct&, IndexSequenceFor<Inner...>>(
|
||||||
|
matchers_));
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::tuple<Inner...> matchers_;
|
||||||
|
};
|
||||||
|
|
||||||
// Implements ElementsAre() and ElementsAreArray().
|
// Implements ElementsAre() and ElementsAreArray().
|
||||||
template <typename Container>
|
template <typename Container>
|
||||||
class ElementsAreMatcherImpl : public MatcherInterface<Container> {
|
class ElementsAreMatcherImpl : public MatcherInterface<Container> {
|
||||||
@ -4514,6 +4711,19 @@ Pair(FirstMatcher first_matcher, SecondMatcher second_matcher) {
|
|||||||
first_matcher, second_matcher);
|
first_matcher, second_matcher);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
namespace no_adl {
|
||||||
|
// FieldsAre(matchers...) matches piecewise the fields of compatible structs.
|
||||||
|
// These include those that support `get<I>(obj)`, and when structured bindings
|
||||||
|
// are enabled any class that supports them.
|
||||||
|
// In particular, `std::tuple`, `std::pair`, `std::array` and aggregate types.
|
||||||
|
template <typename... M>
|
||||||
|
internal::FieldsAreMatcher<typename std::decay<M>::type...> FieldsAre(
|
||||||
|
M&&... matchers) {
|
||||||
|
return internal::FieldsAreMatcher<typename std::decay<M>::type...>(
|
||||||
|
std::forward<M>(matchers)...);
|
||||||
|
}
|
||||||
|
} // namespace no_adl
|
||||||
|
|
||||||
// Returns a predicate that is satisfied by anything that matches the
|
// Returns a predicate that is satisfied by anything that matches the
|
||||||
// given matcher.
|
// given matcher.
|
||||||
template <typename M>
|
template <typename M>
|
||||||
@ -5053,6 +5263,9 @@ PolymorphicMatcher<internal::ExceptionMatcherImpl<Err>> ThrowsMessage(
|
|||||||
#define GMOCK_INTERNAL_MATCHER_ARG_USAGE(i, data_unused, arg_unused) \
|
#define GMOCK_INTERNAL_MATCHER_ARG_USAGE(i, data_unused, arg_unused) \
|
||||||
, gmock_p##i
|
, gmock_p##i
|
||||||
|
|
||||||
|
// To prevent ADL on certain functions we put them on a separate namespace.
|
||||||
|
using namespace no_adl; // NOLINT
|
||||||
|
|
||||||
} // namespace testing
|
} // namespace testing
|
||||||
|
|
||||||
GTEST_DISABLE_MSC_WARNINGS_POP_() // 4251 5046
|
GTEST_DISABLE_MSC_WARNINGS_POP_() // 4251 5046
|
||||||
|
@ -1643,6 +1643,147 @@ TEST(PairTest, InsideContainsUsingMap) {
|
|||||||
EXPECT_THAT(container, Not(Contains(Pair(3, _))));
|
EXPECT_THAT(container, Not(Contains(Pair(3, _))));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST(FieldsAreTest, MatchesCorrectly) {
|
||||||
|
std::tuple<int, std::string, double> p(25, "foo", .5);
|
||||||
|
|
||||||
|
// All fields match.
|
||||||
|
EXPECT_THAT(p, FieldsAre(25, "foo", .5));
|
||||||
|
EXPECT_THAT(p, FieldsAre(Ge(20), HasSubstr("o"), DoubleEq(.5)));
|
||||||
|
|
||||||
|
// Some don't match.
|
||||||
|
EXPECT_THAT(p, Not(FieldsAre(26, "foo", .5)));
|
||||||
|
EXPECT_THAT(p, Not(FieldsAre(25, "fo", .5)));
|
||||||
|
EXPECT_THAT(p, Not(FieldsAre(25, "foo", .6)));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(FieldsAreTest, CanDescribeSelf) {
|
||||||
|
Matcher<const pair<std::string, int>&> m1 = FieldsAre("foo", 42);
|
||||||
|
EXPECT_EQ(
|
||||||
|
"has field #0 that is equal to \"foo\""
|
||||||
|
", and has field #1 that is equal to 42",
|
||||||
|
Describe(m1));
|
||||||
|
EXPECT_EQ(
|
||||||
|
"has field #0 that isn't equal to \"foo\""
|
||||||
|
", or has field #1 that isn't equal to 42",
|
||||||
|
DescribeNegation(m1));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(FieldsAreTest, CanExplainMatchResultTo) {
|
||||||
|
// The first one that fails is the one that gives the error.
|
||||||
|
Matcher<std::tuple<int, int, int>> m =
|
||||||
|
FieldsAre(GreaterThan(0), GreaterThan(0), GreaterThan(0));
|
||||||
|
|
||||||
|
EXPECT_EQ("whose field #0 does not match, which is 1 less than 0",
|
||||||
|
Explain(m, std::make_tuple(-1, -2, -3)));
|
||||||
|
EXPECT_EQ("whose field #1 does not match, which is 2 less than 0",
|
||||||
|
Explain(m, std::make_tuple(1, -2, -3)));
|
||||||
|
EXPECT_EQ("whose field #2 does not match, which is 3 less than 0",
|
||||||
|
Explain(m, std::make_tuple(1, 2, -3)));
|
||||||
|
|
||||||
|
// If they all match, we get a long explanation of success.
|
||||||
|
EXPECT_EQ(
|
||||||
|
"whose all elements match, "
|
||||||
|
"where field #0 is a value which is 1 more than 0"
|
||||||
|
", and field #1 is a value which is 2 more than 0"
|
||||||
|
", and field #2 is a value which is 3 more than 0",
|
||||||
|
Explain(m, std::make_tuple(1, 2, 3)));
|
||||||
|
|
||||||
|
// Only print those that have an explanation.
|
||||||
|
m = FieldsAre(GreaterThan(0), 0, GreaterThan(0));
|
||||||
|
EXPECT_EQ(
|
||||||
|
"whose all elements match, "
|
||||||
|
"where field #0 is a value which is 1 more than 0"
|
||||||
|
", and field #2 is a value which is 3 more than 0",
|
||||||
|
Explain(m, std::make_tuple(1, 0, 3)));
|
||||||
|
|
||||||
|
// If only one has an explanation, then print that one.
|
||||||
|
m = FieldsAre(0, GreaterThan(0), 0);
|
||||||
|
EXPECT_EQ(
|
||||||
|
"whose all elements match, "
|
||||||
|
"where field #1 is a value which is 1 more than 0",
|
||||||
|
Explain(m, std::make_tuple(0, 1, 0)));
|
||||||
|
}
|
||||||
|
|
||||||
|
#if defined(__cpp_structured_bindings) && __cpp_structured_bindings >= 201606
|
||||||
|
TEST(FieldsAreTest, StructuredBindings) {
|
||||||
|
// testing::FieldsAre can also match aggregates and such with C++17 and up.
|
||||||
|
struct MyType {
|
||||||
|
int i;
|
||||||
|
std::string str;
|
||||||
|
};
|
||||||
|
EXPECT_THAT((MyType{17, "foo"}), FieldsAre(Eq(17), HasSubstr("oo")));
|
||||||
|
|
||||||
|
// Test all the supported arities.
|
||||||
|
struct MyVarType1 {
|
||||||
|
int a;
|
||||||
|
};
|
||||||
|
EXPECT_THAT(MyVarType1{}, FieldsAre(0));
|
||||||
|
struct MyVarType2 {
|
||||||
|
int a, b;
|
||||||
|
};
|
||||||
|
EXPECT_THAT(MyVarType2{}, FieldsAre(0, 0));
|
||||||
|
struct MyVarType3 {
|
||||||
|
int a, b, c;
|
||||||
|
};
|
||||||
|
EXPECT_THAT(MyVarType3{}, FieldsAre(0, 0, 0));
|
||||||
|
struct MyVarType4 {
|
||||||
|
int a, b, c, d;
|
||||||
|
};
|
||||||
|
EXPECT_THAT(MyVarType4{}, FieldsAre(0, 0, 0, 0));
|
||||||
|
struct MyVarType5 {
|
||||||
|
int a, b, c, d, e;
|
||||||
|
};
|
||||||
|
EXPECT_THAT(MyVarType5{}, FieldsAre(0, 0, 0, 0, 0));
|
||||||
|
struct MyVarType6 {
|
||||||
|
int a, b, c, d, e, f;
|
||||||
|
};
|
||||||
|
EXPECT_THAT(MyVarType6{}, FieldsAre(0, 0, 0, 0, 0, 0));
|
||||||
|
struct MyVarType7 {
|
||||||
|
int a, b, c, d, e, f, g;
|
||||||
|
};
|
||||||
|
EXPECT_THAT(MyVarType7{}, FieldsAre(0, 0, 0, 0, 0, 0, 0));
|
||||||
|
struct MyVarType8 {
|
||||||
|
int a, b, c, d, e, f, g, h;
|
||||||
|
};
|
||||||
|
EXPECT_THAT(MyVarType8{}, FieldsAre(0, 0, 0, 0, 0, 0, 0, 0));
|
||||||
|
struct MyVarType9 {
|
||||||
|
int a, b, c, d, e, f, g, h, i;
|
||||||
|
};
|
||||||
|
EXPECT_THAT(MyVarType9{}, FieldsAre(0, 0, 0, 0, 0, 0, 0, 0, 0));
|
||||||
|
struct MyVarType10 {
|
||||||
|
int a, b, c, d, e, f, g, h, i, j;
|
||||||
|
};
|
||||||
|
EXPECT_THAT(MyVarType10{}, FieldsAre(0, 0, 0, 0, 0, 0, 0, 0, 0, 0));
|
||||||
|
struct MyVarType11 {
|
||||||
|
int a, b, c, d, e, f, g, h, i, j, k;
|
||||||
|
};
|
||||||
|
EXPECT_THAT(MyVarType11{}, FieldsAre(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0));
|
||||||
|
struct MyVarType12 {
|
||||||
|
int a, b, c, d, e, f, g, h, i, j, k, l;
|
||||||
|
};
|
||||||
|
EXPECT_THAT(MyVarType12{}, FieldsAre(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0));
|
||||||
|
struct MyVarType13 {
|
||||||
|
int a, b, c, d, e, f, g, h, i, j, k, l, m;
|
||||||
|
};
|
||||||
|
EXPECT_THAT(MyVarType13{}, FieldsAre(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0));
|
||||||
|
struct MyVarType14 {
|
||||||
|
int a, b, c, d, e, f, g, h, i, j, k, l, m, n;
|
||||||
|
};
|
||||||
|
EXPECT_THAT(MyVarType14{},
|
||||||
|
FieldsAre(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0));
|
||||||
|
struct MyVarType15 {
|
||||||
|
int a, b, c, d, e, f, g, h, i, j, k, l, m, n, o;
|
||||||
|
};
|
||||||
|
EXPECT_THAT(MyVarType15{},
|
||||||
|
FieldsAre(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0));
|
||||||
|
struct MyVarType16 {
|
||||||
|
int a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p;
|
||||||
|
};
|
||||||
|
EXPECT_THAT(MyVarType16{},
|
||||||
|
FieldsAre(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0));
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
TEST(ContainsTest, WorksWithMoveOnly) {
|
TEST(ContainsTest, WorksWithMoveOnly) {
|
||||||
ContainerHelper helper;
|
ContainerHelper helper;
|
||||||
EXPECT_CALL(helper, Call(Contains(Pointee(2))));
|
EXPECT_CALL(helper, Call(Contains(Pointee(2))));
|
||||||
|
@ -1178,12 +1178,18 @@ struct DoubleSequence<false, IndexSequence<I...>, sizeofT> {
|
|||||||
// Backport of std::make_index_sequence.
|
// Backport of std::make_index_sequence.
|
||||||
// It uses O(ln(N)) instantiation depth.
|
// It uses O(ln(N)) instantiation depth.
|
||||||
template <size_t N>
|
template <size_t N>
|
||||||
struct MakeIndexSequence
|
struct MakeIndexSequenceImpl
|
||||||
: DoubleSequence<N % 2 == 1, typename MakeIndexSequence<N / 2>::type,
|
: DoubleSequence<N % 2 == 1, typename MakeIndexSequenceImpl<N / 2>::type,
|
||||||
N / 2>::type {};
|
N / 2>::type {};
|
||||||
|
|
||||||
template <>
|
template <>
|
||||||
struct MakeIndexSequence<0> : IndexSequence<> {};
|
struct MakeIndexSequenceImpl<0> : IndexSequence<> {};
|
||||||
|
|
||||||
|
template <size_t N>
|
||||||
|
using MakeIndexSequence = typename MakeIndexSequenceImpl<N>::type;
|
||||||
|
|
||||||
|
template <typename... T>
|
||||||
|
using IndexSequenceFor = typename MakeIndexSequence<sizeof...(T)>::type;
|
||||||
|
|
||||||
template <size_t>
|
template <size_t>
|
||||||
struct Ignore {
|
struct Ignore {
|
||||||
|
Loading…
Reference in New Issue
Block a user