将 std::variant 与 gmock 1.8 对象一起使用时出现编译错误
Compile error when using std::variant with gmock 1.8 object
让我们使用 gmock 1.8 编写此代码:
#include "gtest/gtest.h"
#include "gmock/gmock.h"
#include <variant>
class Obj {
public:
MOCK_METHOD0( mock, void() );//<-!!!
};
using Variant = std::variant<Obj>;
TEST(Test, Test) {
Obj obj;
Variant variant = obj;
}
尝试使用 clang++ 编译时出现编译错误:
error: no viable conversion from 'Obj' to 'Variant' (aka 'variant<Obj>')
Variant variant = obj;
^ ~~~
/usr/bin/../lib/gcc/x86_64-linux-gnu/8/../../../../include/c++/8/variant:1081:7: note: candidate constructor not viable: no known conversion from 'Obj' to 'const std::variant<Obj> &' for 1st argument
variant(const variant& __rhs) = default;
^
/usr/bin/../lib/gcc/x86_64-linux-gnu/8/../../../../include/c++/8/variant:1093:2: note: candidate template ignored: substitution failure [with _Tp = Obj &, = void, = void]: implicit instantiation of undefined template 'std::variant<Obj>::__to_type_impl<18446744073709551615, false>'
variant(_Tp&& __t)
^
(g++ 的错误只说
error: conversion from ‘Obj’ to non-scalar type ‘Variant’ {aka ‘std::variant<Obj>’} requested
Variant variant = obj;
^~~
)
注释掉MOCK_METHOD0宏的那一行,代码编译正常。我确信在这种情况下调用的是复制构造函数(第 1081 行中的构造函数)。
这是为什么?如果我移动到 gmock 1.10,问题会消失吗?还是不可能使用 gmock 模拟的变体?感谢您提供有关如何自己找到它的任何解释或提示。
如果展开 MOCK_METHOD0
宏,您将看到它将以下数据成员插入到您的 class 定义中:
class Obj
{
public:
// ...
mutable ::testing::FunctionMocker<void()> gmock0_mock_12;
};
由于您没有提供自己的复制构造函数,编译器将隐式生成一个。它的默认实现将尝试执行成员复制。但是查看FunctionMocker
的定义,可以看到如下提示:
// There is no generally useful and implementable semantics of
// copying a mock object, so copying a mock is usually a user error.
// Thus we disallow copying function mockers. If the user really
// wants to copy a mock object, they should implement their own copy
// operation, for example:
//
// class MockFoo : public Foo {
// public:
// // Defines a copy constructor explicitly.
// MockFoo(const MockFoo& src) {}
// ...
// };
FunctionMocker(const FunctionMocker&) = delete;
FunctionMocker& operator=(const FunctionMocker&) = delete;
也就是说,FunctionMocker
对象是不可复制的,模拟对象也是(它们隐式生成的复制构造函数也被删除)。
这是有道理的。模拟的副本应该有相同的期望吗?它是否应该仔细检查对销毁的期望?
如果您想将 mock 放入一个变体中,您可以就地构建它,或者:
std::variant<Obj> variant(std::in_place_type_t<Obj>{});
或:
std::variant<Obj> variant;
variant.emplace<Obj>();
让我们使用 gmock 1.8 编写此代码:
#include "gtest/gtest.h"
#include "gmock/gmock.h"
#include <variant>
class Obj {
public:
MOCK_METHOD0( mock, void() );//<-!!!
};
using Variant = std::variant<Obj>;
TEST(Test, Test) {
Obj obj;
Variant variant = obj;
}
尝试使用 clang++ 编译时出现编译错误:
error: no viable conversion from 'Obj' to 'Variant' (aka 'variant<Obj>')
Variant variant = obj;
^ ~~~
/usr/bin/../lib/gcc/x86_64-linux-gnu/8/../../../../include/c++/8/variant:1081:7: note: candidate constructor not viable: no known conversion from 'Obj' to 'const std::variant<Obj> &' for 1st argument
variant(const variant& __rhs) = default;
^
/usr/bin/../lib/gcc/x86_64-linux-gnu/8/../../../../include/c++/8/variant:1093:2: note: candidate template ignored: substitution failure [with _Tp = Obj &, = void, = void]: implicit instantiation of undefined template 'std::variant<Obj>::__to_type_impl<18446744073709551615, false>'
variant(_Tp&& __t)
^
(g++ 的错误只说
error: conversion from ‘Obj’ to non-scalar type ‘Variant’ {aka ‘std::variant<Obj>’} requested
Variant variant = obj;
^~~
)
注释掉MOCK_METHOD0宏的那一行,代码编译正常。我确信在这种情况下调用的是复制构造函数(第 1081 行中的构造函数)。
这是为什么?如果我移动到 gmock 1.10,问题会消失吗?还是不可能使用 gmock 模拟的变体?感谢您提供有关如何自己找到它的任何解释或提示。
如果展开 MOCK_METHOD0
宏,您将看到它将以下数据成员插入到您的 class 定义中:
class Obj
{
public:
// ...
mutable ::testing::FunctionMocker<void()> gmock0_mock_12;
};
由于您没有提供自己的复制构造函数,编译器将隐式生成一个。它的默认实现将尝试执行成员复制。但是查看FunctionMocker
的定义,可以看到如下提示:
// There is no generally useful and implementable semantics of
// copying a mock object, so copying a mock is usually a user error.
// Thus we disallow copying function mockers. If the user really
// wants to copy a mock object, they should implement their own copy
// operation, for example:
//
// class MockFoo : public Foo {
// public:
// // Defines a copy constructor explicitly.
// MockFoo(const MockFoo& src) {}
// ...
// };
FunctionMocker(const FunctionMocker&) = delete;
FunctionMocker& operator=(const FunctionMocker&) = delete;
也就是说,FunctionMocker
对象是不可复制的,模拟对象也是(它们隐式生成的复制构造函数也被删除)。
这是有道理的。模拟的副本应该有相同的期望吗?它是否应该仔细检查对销毁的期望?
如果您想将 mock 放入一个变体中,您可以就地构建它,或者:
std::variant<Obj> variant(std::in_place_type_t<Obj>{});
或:
std::variant<Obj> variant;
variant.emplace<Obj>();