我正在尝试编写一个可变参数函数以生成gmock匹配器,以一次检查多个属性的零度。
// Class with three properties.
class Vec3 {
public:
double x() const;
double y() const;
double z() const;
};
using ::testing::AllOf;
using ::testing::Property;
Vec3 vec3;
// I could do this...
EXPECT_THAT(vec3, AllOf(Property(&Vec3::x, Eq(0.0)),
Property(&Vec3::y, Eq(0.0)), Property(&Vec3::z, Eq(0.0)));
// But I'd want to do something like this...
EXPECT_THAT(vec3, PropertiesAreZero(&Vec3::x, &Vec3::y, &Vec3::z));
我似乎无法在编写生成等效匹配器的variardic函数方面取得进展。这是我一直在尝试的方法:
template <typename T, typename M, typename P>
Matcher<T> PropertiesAre(M matcher, P(T::*... args)()) {
return AllOf(Property(args, matcher)...);
};
template <typename T, typename... Others>
Matcher<T> PropertiesAreZero(Others... others) {
return PropertiesAre(Eq(0.0), others...);
}
Vec3 vec3;
EXPECT_THAT(vec3, PropertiesAreZero(&Vec3::x, &Vec3::y, &Vec3::z));
我收到以下编译错误:
error: type 'P (T::*)()' of function parameter pack does not contain any unexpanded parameter packs
Matcher<T> PropertiesAre(M matcher, P(T::*... args)()) {
~~~~~~^~~~~~~~~~~
error: pack expansion does not contain any unexpanded parameter packs
return AllOf(Property(args, matcher)...);
~~~~~~~~~~~~~~~~~~~~~~~^
error: no matching function for call to 'PropertiesAre'
PropertiesAre(Ne(0.0),
^~~~~~~~~~~~~
gmock/include/gmock/gmock-matchers.h:5240:60: note: expanded from macro 'EXPECT_THAT'
::testing::internal::MakePredicateFormatterFromMatcher(matcher), value)
^~~~~~~
gtest/include/gtest/gtest_pred_impl.h:117:23: note: expanded from macro 'EXPECT_PRED_FORMAT1'
GTEST_PRED_FORMAT1_(pred_format, v1, GTEST_NONFATAL_FAILURE_)
^~~~~~~~~~~
gtest/include/gtest/gtest_pred_impl.h:104:17: note: expanded from macro 'GTEST_PRED_FORMAT1_'
GTEST_ASSERT_(pred_format(#v1, v1), \
^~~~~~~~~~~
gtest/include/gtest/gtest_pred_impl.h:80:52: note: expanded from macro 'GTEST_ASSERT_'
if (const ::testing::AssertionResult gtest_ar = (expression)) \
^~~~~~~~~~
note: candidate function template not viable: requires 2 arguments, but 4 were provided
Matcher<T> PropertiesAre(M matcher, P(T::*... args)()) {
^
error: no matching function for call to 'PropertiesAreZero'
PropertiesAreZero(
^~~~~~~~~~~~~~~~~
gmock/include/gmock/gmock-matchers.h:5240:60: note: expanded from macro 'EXPECT_THAT'
::testing::internal::MakePredicateFormatterFromMatcher(matcher), value)
^~~~~~~
gtest/include/gtest/gtest_pred_impl.h:117:23: note: expanded from macro 'EXPECT_PRED_FORMAT1'
GTEST_PRED_FORMAT1_(pred_format, v1, GTEST_NONFATAL_FAILURE_)
^~~~~~~~~~~
gtest/include/gtest/gtest_pred_impl.h:104:17: note: expanded from macro 'GTEST_PRED_FORMAT1_'
GTEST_ASSERT_(pred_format(#v1, v1), \
^~~~~~~~~~~
gtest/include/gtest/gtest_pred_impl.h:80:52: note: expanded from macro 'GTEST_ASSERT_'
if (const ::testing::AssertionResult gtest_ar = (expression)) \
^~~~~~~~~~
note: candidate template ignored: couldn't infer template argument 'T'
Matcher<T> PropertiesAreZero(Others... others) {
^
error: no matching function for call to 'PropertiesAreZero'
PropertiesAreZero(
^~~~~~~~~~~~~~~~~
我真的很感谢我能为此提供的任何帮助。我已经整整整整整整一整天地在面对这一问题。
最佳答案
在没有AllOf
之类的定义的情况下,要使其完全正确是有些棘手的事情,但这是我想要的目的,然后我将尝试解释您的错误所在。
template<typename R, typename T>
using const_member_ptr = R(T::*)() const;
template<typename T, typename M, typename... R>
Matcher<T> PropertiesAre(M matcher, const_member_ptr<R,T> ...args)
{
return AllOf<T>(Property(args, matcher)...);
}
template <typename T, typename... R>
Matcher<T> PropertiesAreZero(const_member_ptr<R,T>... others)
{
return PropertiesAre<T>(Eq(0.0), others...);
}
第一个问题是在您的
PropertiesAreZero
版本中,编译器无法推断出T
是什么。编译器必须能够从函数的参数推断出,因此您必须给它一些模式匹配的依据。在这种情况下,我假设您正在调用const成员函数,并且当编译器对此进行模式匹配时,它可以推断T
。由于我们有了
T
,因此即使我们可以再次推断出它,我也将其显式提供给PropertiesAre
。 PropertiesAre
的问题在于,您可以使用省略号来扩展参数包,但实际上它不是可变参数模板。我已经通过使R模板参数可变而修复了该问题。作为引用,这些是我猜到的定义:
template<typename T>
class Matcher{};
struct Eq
{ Eq(double){} };
template<typename T, typename... X>
Matcher<T> AllOf(X ...x) {}
template<typename P, typename M>
int Property(P p, M m) {}
并在Godbolt上编译。
关于c++ - 可变参数模板中的类成员函数,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/49217891/