Использование std::any с gmock приводит к другому поведению на gcc 7 и 9

Я пытался смоделировать шаблонную функцию в классе и найти хороший пример в этом вопросе

Поэтому я попытался использовать std::any с googlemock, и ниже код подходит.

#include <any>
#include <gmock/gmock.h>
#include <gtest/gtest.h>

using ::testing::Return;

class Base
{
  public:
    virtual ~Base() = default;

    template<typename T>
    T GetData() const
    {
        auto data = GetDataImpl();
        return std::any_cast<T>(data);
    }
    virtual std::any GetDataImpl() const = 0;
};

class BaseMock : public Base
{
  public:
    virtual ~BaseMock() = default;
    MOCK_CONST_METHOD0(GetDataImpl, std::any());
};

const Base& GetBase()
{
    static BaseMock base;
    return base;
}

template<typename T>
T GetData()
{
    return GetBase().GetData<T>();
}


TEST(MyTest, BaseReturnBool)
{
    const auto& base = reinterpret_cast<const BaseMock&>(GetBase());
    EXPECT_CALL(base, GetDataImpl()).WillOnce(Return(std::any(true)));
    EXPECT_TRUE(GetData<bool>());
}

TEST(MyTest, BaseReturnString)
{
    const auto& base = reinterpret_cast<const BaseMock&>(GetBase());
    EXPECT_CALL(base, GetDataImpl()).WillOnce(Return(std::any(std::string("test"))));
    EXPECT_EQ(GetData<std::string>(), "test");
}

Он отлично работает с GCC7.4.0 на Ubuntu 18.04, с gtest release-1.8.1.

$ g++ --version
g++ (Ubuntu 7.4.0-1ubuntu1~18.04) 7.4.0
...

$ g++ -std=c++17 -o utest test_gmock_with_std_any.cpp -lgmock -lgtest -lgtest_main -pthread

Но это не в состоянии построить на GCC 9.1.0:

$ g++-9 --version
g++-9 (Ubuntu 9.1.0-2ubuntu2~18.04) 9.1.0
...

$ g++-9 -std=c++17 -o utest test_gmock_with_std_any.cpp -lgmock -lgtest -lgtest_main -pthread
In file included from /usr/include/c++/9/bits/move.h:55,
                 from /usr/include/c++/9/bits/nested_exception.h:40,
                 from /usr/include/c++/9/exception:144,
                 from /usr/include/c++/9/new:40,
                 from /usr/include/c++/9/any:37,
                 from test_gmock_with_std_any.cpp:1:
/usr/include/c++/9/type_traits: In instantiation of ‘struct std::__and_<std::is_copy_constructible<testing::internal::ReferenceOrValueWrapper<std::any> >, std::is_constructible<testing::internal::ReferenceOrValueWrapper<std::any>, const testing::internal::ReferenceOrValueWrapper<std::any>&> >’:
/usr/include/c++/9/any:181:58:   required by substitution of ‘template<class _ValueType, class _Tp, class _Mgr, typename std::enable_if<std::__and_<std::is_copy_constructible<_Tp>, std::is_construct
ible<_Tp, _ValueType&&> >::value, bool>::type <anonymous>, typename std::enable_if<(! std::__is_in_place_type<_Tp>::value), bool>::type <anonymous> > std::any::any(_ValueType&&) [with _ValueType = const testing::internal::ReferenceOrValueWrapper<std::any>&; _Tp = testing::internal::ReferenceOrValueWrapper<std::any>; _Mgr = std::any::_Manager_external<testing::internal::ReferenceOrValueWrapper<
std::any> >; typename std::enable_if<std::__and_<std::is_copy_constructible<_Tp>, std::is_constructible<_Tp, _ValueType&&> >::value, bool>::type <anonymous> = <missing>; typename std::enable_if<(! s
td::__is_in_place_type<_Tp>::value), bool>::type <anonymous> = <missing>]’
/usr/include/c++/9/type_traits:883:12:   required from ‘struct std::is_constructible<testing::internal::ReferenceOrValueWrapper<std::any>, const testing::internal::ReferenceOrValueWrapper<std::any>&
>’
/usr/include/c++/9/type_traits:901:12:   required from ‘struct std::__is_copy_constructible_impl<testing::internal::ReferenceOrValueWrapper<std::any>, true>’
/usr/include/c++/9/type_traits:907:12:   required from ‘struct std::is_copy_constructible<testing::internal::ReferenceOrValueWrapper<std::any> >’
/usr/include/c++/9/type_traits:131:12:   required from ‘struct std::__and_<std::is_copy_constructible<testing::internal::ReferenceOrValueWrapper<std::any> >, std::is_constructible<testing::internal:
:ReferenceOrValueWrapper<std::any>, testing::internal::ReferenceOrValueWrapper<std::any>&&> >’
/usr/include/c++/9/any:181:58:   required by substitution of ‘template<class _ValueType, class _Tp, class _Mgr, typename std::enable_if<std::__and_<std::is_copy_constructible<_Tp>, std::is_constructible<_Tp, _ValueType&&> >::value, bool>::type <anonymous>, typename std::enable_if<(! std::__is_in_place_type<_Tp>::value), bool>::type <anonymous> > std::any::any(_ValueType&&) [with _ValueType = testing::internal::ReferenceOrValueWrapper<std::any>; _Tp = testing::internal::ReferenceOrValueWrapper<std::any>; _Mgr = std::any::_Manager_external<testing::internal::ReferenceOrValueWrapper<std::an
y> >; typename std::enable_if<std::__and_<std::is_copy_constructible<_Tp>, std::is_constructible<_Tp, _ValueType&&> >::value, bool>::type <anonymous> = <missing>; typename std::enable_if<(! std::__is_in_place_type<_Tp>::value), bool>::type <anonymous> = <missing>]’
/usr/local/include/gmock/gmock-spec-builders.h:1423:50:   required from ‘testing::internal::ActionResultHolder<T>::ActionResultHolder(testing::internal::ActionResultHolder<T>::Wrapper) [with T = std
::any; testing::internal::ActionResultHolder<T>::Wrapper = testing::internal::ReferenceOrValueWrapper<std::any>]’
/usr/local/include/gmock/gmock-spec-builders.h:1405:12:   required from ‘static testing::internal::ActionResultHolder<T>* testing::internal::ActionResultHolder<T>::PerformDefaultAction(const testing::internal::FunctionMockerBase<F>*, typename testing::internal::RvalueRef<typename testing::internal::Function<F>::ArgumentTuple>::type, const string&) [with F = std::any(); T = std::any; typename t
esting::internal::RvalueRef<typename testing::internal::Function<F>::ArgumentTuple>::type = std::tuple<>&&; std::string = std::__cxx11::basic_string<char>]’
/usr/local/include/gmock/gmock-spec-builders.h:1542:46:   required from ‘testing::internal::UntypedActionResultHolderBase* testing::internal::FunctionMockerBase<F>::UntypedPerformDefaultAction(void*, const string&) const [with F = std::any(); std::string = std::__cxx11::basic_string<char>]’
/usr/local/include/gmock/gmock-spec-builders.h:1538:42:   required from here
/usr/include/c++/9/type_traits:131:12: error: incomplete type ‘std::is_copy_constructible<testing::internal::ReferenceOrValueWrapper<std::any> >’ used in nested name specifier
  131 |     struct __and_<_B1, _B2>
      |            ^~~~~~~~~~~~~~~~
/usr/include/c++/9/type_traits: In instantiation of ‘struct std::__and_<std::is_copy_constructible<testing::internal::ReferenceOrValueWrapper<std::any> >, std::__not_<std::is_constructible<testing::
internal::ReferenceOrValueWrapper<std::any>, const testing::internal::ReferenceOrValueWrapper<std::any>&> >, std::__not_<std::__is_in_place_type<testing::internal::ReferenceOrValueWrapper<std::any> > > >’:
/usr/include/c++/9/type_traits:150:27:   required from ‘constexpr const bool std::__and_v<std::is_copy_constructible<testing::internal::ReferenceOrValueWrapper<std::any> >, std::__not_<std::is_const
ructible<testing::internal::ReferenceOrValueWrapper<std::any>, const testing::internal::ReferenceOrValueWrapper<std::any>&> >, std::__not_<std::__is_in_place_type<testing::internal::ReferenceOrValue
Wrapper<std::any> > > >’
/usr/include/c++/9/any:192:27:   required by substitution of ‘template<class _ValueType, class _Tp, class _Mgr, typename std::enable_if<__and_v<std::is_copy_constructible<_Tp>, std::__not_<std::is_c
onstructible<_Tp, _ValueType&&> >, std::__not_<std::__is_in_place_type<_Tp> > >, bool>::type <anonymous> > std::any::any(_ValueType&&) [with _ValueType = const testing::internal::ReferenceOrValueWra
pper<std::any>&; _Tp = testing::internal::ReferenceOrValueWrapper<std::any>; _Mgr = std::any::_Manager_external<testing::internal::ReferenceOrValueWrapper<std::any> >; typename std::enable_if<__and_
v<std::is_copy_constructible<_Tp>, std::__not_<std::is_constructible<_Tp, _ValueType&&> >, std::__not_<std::__is_in_place_type<_Tp> > >, bool>::type <anonymous> = <missing>]’
/usr/include/c++/9/type_traits:883:12:   required from ‘struct std::is_constructible<testing::internal::ReferenceOrValueWrapper<std::any>, const testing::internal::ReferenceOrValueWrapper<std::any>&
>’                                                                                                                                                                                                    /usr/include/c++/9/type_traits:901:12:   required from ‘struct std::__is_copy_constructible_impl<testing::internal::ReferenceOrValueWrapper<std::any>, true>’                                         /usr/include/c++/9/type_traits:907:12:   required from ‘struct std::is_copy_constructible<testing::internal::ReferenceOrValueWrapper<std::any> >’
/usr/include/c++/9/type_traits:131:12:   required from ‘struct std::__and_<std::is_copy_constructible<testing::internal::ReferenceOrValueWrapper<std::any> >, std::is_constructible<testing::internal::ReferenceOrValueWrapper<std::any>, testing::internal::ReferenceOrValueWrapper<std::any>&&> >’
/usr/include/c++/9/any:181:58:   required by substitution of ‘template<class _ValueType, class _Tp, class _Mgr, typename std::enable_if<std::__and_<std::is_copy_constructible<_Tp>, std::is_construct
ible<_Tp, _ValueType&&> >::value, bool>::type <anonymous>, typename std::enable_if<(! std::__is_in_place_type<_Tp>::value), bool>::type <anonymous> > std::any::any(_ValueType&&) [with _ValueType = t
esting::internal::ReferenceOrValueWrapper<std::any>; _Tp = testing::internal::ReferenceOrValueWrapper<std::any>; _Mgr = std::any::_Manager_external<testing::internal::ReferenceOrValueWrapper<std::any> >; typename std::enable_if<std::__and_<std::is_copy_constructible<_Tp>, std::is_constructible<_Tp, _ValueType&&> >::value, bool>::type <anonymous> = <missing>; typename std::enable_if<(! std::__i
s_in_place_type<_Tp>::value), bool>::type <anonymous> = <missing>]’
/usr/local/include/gmock/gmock-spec-builders.h:1423:50:   required from ‘testing::internal::ActionResultHolder<T>::ActionResultHolder(testing::internal::ActionResultHolder<T>::Wrapper) [with T = std::any; testing::internal::ActionResultHolder<T>::Wrapper = testing::internal::ReferenceOrValueWrapper<std::any>]’
/usr/local/include/gmock/gmock-spec-builders.h:1405:12:   required from ‘static testing::internal::ActionResultHolder<T>* testing::internal::ActionResultHolder<T>::PerformDefaultAction(const testing
::internal::FunctionMockerBase<F>*, typename testing::internal::RvalueRef<typename testing::internal::Function<F>::ArgumentTuple>::type, const string&) [with F = std::any(); T = std::any; typename t
esting::internal::RvalueRef<typename testing::internal::Function<F>::ArgumentTuple>::type = std::tuple<>&&; std::string = std::__cxx11::basic_string<char>]’
/usr/local/include/gmock/gmock-spec-builders.h:1542:46:   required from ‘testing::internal::UntypedActionResultHolderBase* testing::internal::FunctionMockerBase<F>::UntypedPerformDefaultAction(void*
, const string&) const [with F = std::any(); std::string = std::__cxx11::basic_string<char>]’                                                                                                         /usr/local/include/gmock/gmock-spec-builders.h:1538:42:   required from here                                                                                                                          /usr/include/c++/9/type_traits:136:12: error: incomplete type ‘std::is_copy_constructible<testing::internal::ReferenceOrValueWrapper<std::any> >’ used in nested name specifier
  136 |     struct __and_<_B1, _B2, _B3, _Bn...>                                                                                                                                                            |            ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/usr/include/c++/9/type_traits: In instantiation of ‘constexpr const bool std::__and_v<std::is_copy_constructible<testing::internal::ReferenceOrValueWrapper<std::any> >, std::__not_<std::is_construc
tible<testing::internal::ReferenceOrValueWrapper<std::any>, const testing::internal::ReferenceOrValueWrapper<std::any>&> >, std::__not_<std::__is_in_place_type<testing::internal::ReferenceOrValueWrapper<std::any> > > >’:                                                                                                                                                                                /usr/include/c++/9/any:192:27:   required by substitution of ‘template<class _ValueType, class _Tp, class _Mgr, typename std::enable_if<__and_v<std::is_copy_constructible<_Tp>, std::__not_<std::is_c
onstructible<_Tp, _ValueType&&> >, std::__not_<std::__is_in_place_type<_Tp> > >, bool>::type <anonymous> > std::any::any(_ValueType&&) [with _ValueType = const testing::internal::ReferenceOrValueWra
pper<std::any>&; _Tp = testing::internal::ReferenceOrValueWrapper<std::any>; _Mgr = std::any::_Manager_external<testing::internal::ReferenceOrValueWrapper<std::any> >; typename std::enable_if<__and_
v<std::is_copy_constructible<_Tp>, std::__not_<std::is_constructible<_Tp, _ValueType&&> >, std::__not_<std::__is_in_place_type<_Tp> > >, bool>::type <anonymous> = <missing>]’
/usr/include/c++/9/type_traits:883:12:   required from ‘struct std::is_constructible<testing::internal::ReferenceOrValueWrapper<std::any>, const testing::internal::ReferenceOrValueWrapper<std::any>&
>’
/usr/include/c++/9/type_traits:901:12:   required from ‘struct std::__is_copy_constructible_impl<testing::internal::ReferenceOrValueWrapper<std::any>, true>’
/usr/include/c++/9/type_traits:907:12:   required from ‘struct std::is_copy_constructible<testing::internal::ReferenceOrValueWrapper<std::any> >’
/usr/include/c++/9/type_traits:131:12:   required from ‘struct std::__and_<std::is_copy_constructible<testing::internal::ReferenceOrValueWrapper<std::any> >, std::is_constructible<testing::internal::ReferenceOrValueWrapper<std::any>, testing::internal::ReferenceOrValueWrapper<std::any>&&> >’
/usr/include/c++/9/any:181:58:   required by substitution of ‘template<class _ValueType, class _Tp, class _Mgr, typename std::enable_if<std::__and_<std::is_copy_constructible<_Tp>, std::is_construct
ible<_Tp, _ValueType&&> >::value, bool>::type <anonymous>, typename std::enable_if<(! std::__is_in_place_type<_Tp>::value), bool>::type <anonymous> > std::any::any(_ValueType&&) [with _ValueType = testing::internal::ReferenceOrValueWrapper<std::any>; _Tp = testing::internal::ReferenceOrValueWrapper<std::any>; _Mgr = std::any::_Manager_external<testing::internal::ReferenceOrValueWrapper<std::an
y> >; typename std::enable_if<std::__and_<std::is_copy_constructible<_Tp>, std::is_constructible<_Tp, _ValueType&&> >::value, bool>::type <anonymous> = <missing>; typename std::enable_if<(! std::__i
s_in_place_type<_Tp>::value), bool>::type <anonymous> = <missing>]’
/usr/local/include/gmock/gmock-spec-builders.h:1423:50:   required from ‘testing::internal::ActionResultHolder<T>::ActionResultHolder(testing::internal::ActionResultHolder<T>::Wrapper) [with T = std
::any; testing::internal::ActionResultHolder<T>::Wrapper = testing::internal::ReferenceOrValueWrapper<std::any>]’
/usr/local/include/gmock/gmock-spec-builders.h:1405:12:   required from ‘static testing::internal::ActionResultHolder<T>* testing::internal::ActionResultHolder<T>::PerformDefaultAction(const testing::internal::FunctionMockerBase<F>*, typename testing::internal::RvalueRef<typename testing::internal::Function<F>::ArgumentTuple>::type, const string&) [with F = std::any(); T = std::any; typename testing::internal::RvalueRef<typename testing::internal::Function<F>::ArgumentTuple>::type = std::tuple<>&&; std::string = std::__cxx11::basic_string<char>]’
/usr/local/include/gmock/gmock-spec-builders.h:1542:46:   required from ‘testing::internal::UntypedActionResultHolderBase* testing::internal::FunctionMockerBase<F>::UntypedPerformDefaultAction(void*, const string&) const [with F = std::any(); std::string = std::__cxx11::basic_string<char>]’
/usr/local/include/gmock/gmock-spec-builders.h:1538:42:   required from here
/usr/include/c++/9/type_traits:150:27: error: ‘value’ is not a member of ‘std::__and_<std::is_copy_constructible<testing::internal::ReferenceOrValueWrapper<std::any> >, std::__not_<std::is_constructible<testing::internal::ReferenceOrValueWrapper<std::any>, const testing::internal::ReferenceOrValueWrapper<std::any>&> >, std::__not_<std::__is_in_place_type<testing::internal::ReferenceOrValueWrapper<std::any> > > >’
  150 |     inline constexpr bool __and_v = __and_<_Bn...>::value;

Итак, вопросы:

  1. Вышеуказанный код действителен или нет?
  2. Если это верно, что не так с проблемой? Может быть, ошибка в gcc-9?

[Обновить]

Похоже, первопричину проблемы можно упростить до приведенного ниже кода, где ReferenceOrValueWrapper это класс в gmock.

#include <any>
#include <cstdio>

template <typename T>
class ReferenceOrValueWrapper {
 public:
  explicit ReferenceOrValueWrapper(T value)
      : value_(std::move(value)) {
  }
  T Unwrap() { return std::move(value_); }
  const T& Peek() const {
    return value_;
  }
 private:
  T value_;
};

template <typename T>
class ReferenceOrValueWrapper<T&> {
 public:
  typedef T& reference;
  explicit ReferenceOrValueWrapper(reference ref)
      : value_ptr_(&ref) {}
  T& Unwrap() { return *value_ptr_; }
  const T& Peek() const { return *value_ptr_; }
 private:
  T* value_ptr_;
};

int main()
{
    // Below code generates the same error
    constexpr bool b = std::is_copy_constructible<ReferenceOrValueWrapper<std::any>>::value;
    printf("b: %d\n", b);
}

Когда мы ставим std::any в ReferenceOrValueWrapperпроблема в том, что ни один член не назван value в std::is_copy_constructible<ReferenceOrValueWrapper<std::any>>

0 ответов

Другие вопросы по тегам