Let's have this code using 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;
}
When trying to compile this with clang++ there is this compile error:
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 &, $1 = void, $2 = void]: implicit instantiation of undefined template 'std::variant<Obj>::__to_type_impl<18446744073709551615, false>'
variant(_Tp&& __t)
^
(g++'s error only says
error: conversion from ‘Obj’ to non-scalar type ‘Variant’ {aka ‘std::variant<Obj>’} requested
Variant variant = obj;
^~~
)
When the line with MOCK_METHOD0 macro is commented out, the code compiles all right. I'm convinced it's the copy constructor (the one from line 1081) that gets invoked in that case.
Why is that? Will the problem disappear if I move to gmock 1.10? Or is it impossible to use variants of gmock mocks? Thanks for any explanation or a hint on how to find it myself.
If you expand the MOCK_METHOD0
macro, you will see that it inserts the following data member to your class definition:
class Obj
{
public:
// ...
mutable ::testing::FunctionMocker<void()> gmock0_mock_12;
};
Since you do not provide your own copy-constructor, one will be implicitly generated by the compiler. Its default implementation will try to perform a member-wise copy. However, checking the definition of FunctionMocker
, one can see the following notice:
// 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;
That is, FunctionMocker
objects are non-copyable, and so are mock objects (their implicitly generated copy-constructors are also deleted).
That's reasonable. Should a copy of a mock have the same expectations? Should it double-check the expectations on destruction?
If you want to put the mock in a variant, you can build it in-place, either:
std::variant<Obj> variant(std::in_place_type_t<Obj>{});
or:
std::variant<Obj> variant;
variant.emplace<Obj>();