将 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>();