使用右值参数调用函数时出现 Gtest 编译器错误

Gtest compiler error when invoking function with rvalue argument

看在上帝的份上,我无法理解这个编译器错误试图告诉我什么:

转载于 godbolt:https://godbolt.org/z/v3M5hEbdv

#include "gtest/gtest.h"
#include "gmock/gmock.h"

#include <string>
#include <functional>
#include <vector>

class MyService {
public:
    virtual ~MyService() = default;
    virtual void bar(
        std::function<void (std::vector<std::string>&&)> onSuccess
    ) = 0;
};


class MyServiceMock : public MyService
{
public:
    MOCK_METHOD(
        void,
        bar,
        (std::function<void(std::vector<std::string>&&)> onSuccess),
        (override)
    );
};

[[maybe_unused]]
void foo() {
    testing::NiceMock<MyServiceMock> myService;
    EXPECT_CALL(myService, bar(testing::_))
        .Times(testing::Exactly(1))
        .WillOnce(testing::DoAll(
            testing::Return(),
            testing::InvokeArgument<0>(
               std::vector<std::string>({"hello", "world"})
            )
        ));
}

int main() {
    return 0;
}

编译错误:


Output of x86-64 gcc 11.2 (Compiler #1)
In file included from /opt/compiler-explorer/gcc-11.2.0/include/c++/11.2.0/bits/unique_ptr.h:37,
                 from /opt/compiler-explorer/gcc-11.2.0/include/c++/11.2.0/memory:76,
                 from /opt/compiler-explorer/libs/googletest/trunk/googletest/include/gtest/gtest.h:55,
                 from <source>:1:
/opt/compiler-explorer/gcc-11.2.0/include/c++/11.2.0/tuple: In instantiation of 'struct std::tuple_element<0, std::tuple<> >':
/opt/compiler-explorer/gcc-11.2.0/include/c++/11.2.0/utility:118:11:   required by substitution of 'template<long unsigned int __i, class _Tp> using __tuple_element_t = typename std::tuple_element::type [with long unsigned int __i = 0; _Tp = std::tuple<>]'
/opt/compiler-explorer/gcc-11.2.0/include/c++/11.2.0/tuple:1403:5:   required by substitution of 'template<long unsigned int __i, class ... _Elements> constexpr std::__tuple_element_t<__i, std::tuple<_UTypes ...> >&& std::get(const std::tuple<_UTypes ...>&&) [with long unsigned int __i = 0; _Elements = {}]'
/opt/compiler-explorer/libs/googletest/trunk/googlemock/include/gmock/gmock-more-actions.h:515:22:   required by substitution of 'template<class ... Args> decltype (testing::internal::InvokeArgument(get<0>(std::forward_as_tuple((forward<Args>)(testing::internal::InvokeArgumentAction<index, Params ...>::operator()::args)...)), declval<const std::vector<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > >&>())) testing::internal::InvokeArgumentAction<0, std::vector<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > > >::operator()<Args ...>(Args&& ...) const [with Args = {}]'
/opt/compiler-explorer/gcc-11.2.0/include/c++/11.2.0/type_traits:2466:26:   required by substitution of 'template<class _Fn, class ... _Args> static std::__result_of_success<decltype (declval<_Fn>()((declval<_Args>)()...)), std::__invoke_other> std::__result_of_other_impl::_S_test(int) [with _Fn = testing::internal::InvokeArgumentAction<0, std::vector<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > > >&; _Args = {}]'
/opt/compiler-explorer/gcc-11.2.0/include/c++/11.2.0/type_traits:2477:55:   required from 'struct std::__result_of_impl<false, false, testing::internal::InvokeArgumentAction<0, std::vector<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > > >&>'
/opt/compiler-explorer/gcc-11.2.0/include/c++/11.2.0/type_traits:2482:12:   [ skipping 3 instantiation contexts, use -ftemplate-backtrace-limit=0 to disable ]
/opt/compiler-explorer/gcc-11.2.0/include/c++/11.2.0/bits/std_function.h:344:8:   required by substitution of 'template<class _Res, class ... _ArgTypes> template<class _Cond, class _Tp> using _Requires = typename std::enable_if<_Cond::value, _Tp>::type [with _Cond = std::function<void()>::_Callable<testing::internal::InvokeArgumentAction<0, std::vector<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > > >, std::__invoke_result<testing::internal::InvokeArgumentAction<0, std::vector<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > > >&> >; _Tp = void; _Res = void; _ArgTypes = {}]'
/opt/compiler-explorer/gcc-11.2.0/include/c++/11.2.0/bits/std_function.h:413:9:   required by substitution of 'template<class _Functor, class, class> std::function<void()>::function(_Functor) [with _Functor = testing::internal::InvokeArgumentAction<0, std::vector<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > > >; <template-parameter-1-2> = void; <template-parameter-1-3> = <missing>]'
/opt/compiler-explorer/gcc-11.2.0/include/c++/11.2.0/type_traits:906:30:   required from 'struct std::__is_constructible_impl<std::function<void()>, const testing::internal::InvokeArgumentAction<0, std::vector<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > > >&>'
/opt/compiler-explorer/gcc-11.2.0/include/c++/11.2.0/type_traits:911:12:   required from 'struct std::is_constructible<std::function<void()>, const testing::internal::InvokeArgumentAction<0, std::vector<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > > >&>'
/opt/compiler-explorer/libs/googletest/trunk/googlemock/include/gmock/gmock-actions.h:466:7:   required by substitution of 'template<class G, class> testing::Action<void(std::function<void(std::vector<std::__cxx11::basic_string<char> >&&)>)>::Action(G&&) [with G = const testing::internal::InvokeArgumentAction<0, std::vector<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > > >&; <template-parameter-1-2> = <missing>]'
/opt/compiler-explorer/libs/googletest/trunk/googlemock/include/gmock/gmock-actions.h:1061:56:   required from 'testing::internal::DoAllAction<Actions>::operator testing::Action<R(Args ...)>() const [with R = void; Args = {std::function<void(std::vector<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > >&&)>}; Actions = {testing::PolymorphicAction<testing::internal::ReturnVoidAction>, testing::internal::InvokeArgumentAction<0, std::vector<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > > >}]'
<source>:33:18:   required from here
/opt/compiler-explorer/gcc-11.2.0/include/c++/11.2.0/tuple:1360:25: error: static assertion failed: tuple index must be in range
 1360 |       static_assert(__i < tuple_size<tuple<>>::value,
      |                     ~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~
/opt/compiler-explorer/gcc-11.2.0/include/c++/11.2.0/tuple:1360:25: note: '(0 < ((long unsigned int)std::integral_constant<long unsigned int, 0>::value))' evaluates to false
In file included from /opt/compiler-explorer/libs/googletest/trunk/googlemock/include/gmock/gmock.h:57,
                 from <source>:2:
/opt/compiler-explorer/libs/googletest/trunk/googlemock/include/gmock/gmock-actions.h: In instantiation of 'testing::internal::DoAllAction<Actions>::operator testing::Action<R(Args ...)>() const [with R = void; Args = {std::function<void(std::vector<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > >&&)>}; Actions = {testing::PolymorphicAction<testing::internal::ReturnVoidAction>, testing::internal::InvokeArgumentAction<0, std::vector<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > > >}]':
<source>:33:18:   required from here
/opt/compiler-explorer/libs/googletest/trunk/googlemock/include/gmock/gmock-actions.h:1061:56: error: could not convert 'std::get<1, testing::PolymorphicAction<testing::internal::ReturnVoidAction>, testing::internal::InvokeArgumentAction<0, std::vector<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > > > >(((const testing::internal::DoAllAction<testing::PolymorphicAction<testing::internal::ReturnVoidAction>, testing::internal::InvokeArgumentAction<0, std::vector<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > > > >*)this)->testing::internal::DoAllAction<testing::PolymorphicAction<testing::internal::ReturnVoidAction>, testing::internal::InvokeArgumentAction<0, std::vector<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > > > >::actions)' from 'std::__tuple_element_t<1, std::tuple<testing::PolymorphicAction<testing::internal::ReturnVoidAction>, testing::internal::InvokeArgumentAction<0, std::vector<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > > > > >' {aka 'const testing::internal::InvokeArgumentAction<0, std::vector<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > > >'} to 'testing::Action<void(std::function<void(std::vector<std::__cxx11::basic_string<char> >&&)>)>'
 1061 |               std::get<sizeof...(Actions) - 1>(actions)};
      |                                                        ^
      |                                                        |
      |                                                        std::__tuple_element_t<1, std::tuple<testing::PolymorphicAction<testing::internal::ReturnVoidAction>, testing::internal::InvokeArgumentAction<0, std::vector<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > > > > > {aka const testing::internal::InvokeArgumentAction<0, std::vector<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > > >}
ASM generation compiler returned: 1
In file included from /opt/compiler-explorer/gcc-11.2.0/include/c++/11.2.0/bits/unique_ptr.h:37,
                 from /opt/compiler-explorer/gcc-11.2.0/include/c++/11.2.0/memory:76,
                 from /opt/compiler-explorer/libs/googletest/trunk/googletest/include/gtest/gtest.h:55,
                 from <source>:1:
/opt/compiler-explorer/gcc-11.2.0/include/c++/11.2.0/tuple: In instantiation of 'struct std::tuple_element<0, std::tuple<> >':
/opt/compiler-explorer/gcc-11.2.0/include/c++/11.2.0/utility:118:11:   required by substitution of 'template<long unsigned int __i, class _Tp> using __tuple_element_t = typename std::tuple_element::type [with long unsigned int __i = 0; _Tp = std::tuple<>]'
/opt/compiler-explorer/gcc-11.2.0/include/c++/11.2.0/tuple:1403:5:   required by substitution of 'template<long unsigned int __i, class ... _Elements> constexpr std::__tuple_element_t<__i, std::tuple<_UTypes ...> >&& std::get(const std::tuple<_UTypes ...>&&) [with long unsigned int __i = 0; _Elements = {}]'
/opt/compiler-explorer/libs/googletest/trunk/googlemock/include/gmock/gmock-more-actions.h:515:22:   required by substitution of 'template<class ... Args> decltype (testing::internal::InvokeArgument(get<0>(std::forward_as_tuple((forward<Args>)(testing::internal::InvokeArgumentAction<index, Params ...>::operator()::args)...)), declval<const std::vector<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > >&>())) testing::internal::InvokeArgumentAction<0, std::vector<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > > >::operator()<Args ...>(Args&& ...) const [with Args = {}]'
/opt/compiler-explorer/gcc-11.2.0/include/c++/11.2.0/type_traits:2466:26:   required by substitution of 'template<class _Fn, class ... _Args> static std::__result_of_success<decltype (declval<_Fn>()((declval<_Args>)()...)), std::__invoke_other> std::__result_of_other_impl::_S_test(int) [with _Fn = testing::internal::InvokeArgumentAction<0, std::vector<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > > >&; _Args = {}]'
/opt/compiler-explorer/gcc-11.2.0/include/c++/11.2.0/type_traits:2477:55:   required from 'struct std::__result_of_impl<false, false, testing::internal::InvokeArgumentAction<0, std::vector<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > > >&>'
/opt/compiler-explorer/gcc-11.2.0/include/c++/11.2.0/type_traits:2482:12:   [ skipping 3 instantiation contexts, use -ftemplate-backtrace-limit=0 to disable ]
/opt/compiler-explorer/gcc-11.2.0/include/c++/11.2.0/bits/std_function.h:344:8:   required by substitution of 'template<class _Res, class ... _ArgTypes> template<class _Cond, class _Tp> using _Requires = typename std::enable_if<_Cond::value, _Tp>::type [with _Cond = std::function<void()>::_Callable<testing::internal::InvokeArgumentAction<0, std::vector<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > > >, std::__invoke_result<testing::internal::InvokeArgumentAction<0, std::vector<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > > >&> >; _Tp = void; _Res = void; _ArgTypes = {}]'
/opt/compiler-explorer/gcc-11.2.0/include/c++/11.2.0/bits/std_function.h:413:9:   required by substitution of 'template<class _Functor, class, class> std::function<void()>::function(_Functor) [with _Functor = testing::internal::InvokeArgumentAction<0, std::vector<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > > >; <template-parameter-1-2> = void; <template-parameter-1-3> = <missing>]'
/opt/compiler-explorer/gcc-11.2.0/include/c++/11.2.0/type_traits:906:30:   required from 'struct std::__is_constructible_impl<std::function<void()>, const testing::internal::InvokeArgumentAction<0, std::vector<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > > >&>'
/opt/compiler-explorer/gcc-11.2.0/include/c++/11.2.0/type_traits:911:12:   required from 'struct std::is_constructible<std::function<void()>, const testing::internal::InvokeArgumentAction<0, std::vector<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > > >&>'
/opt/compiler-explorer/libs/googletest/trunk/googlemock/include/gmock/gmock-actions.h:466:7:   required by substitution of 'template<class G, class> testing::Action<void(std::function<void(std::vector<std::__cxx11::basic_string<char> >&&)>)>::Action(G&&) [with G = const testing::internal::InvokeArgumentAction<0, std::vector<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > > >&; <template-parameter-1-2> = <missing>]'
/opt/compiler-explorer/libs/googletest/trunk/googlemock/include/gmock/gmock-actions.h:1061:56:   required from 'testing::internal::DoAllAction<Actions>::operator testing::Action<R(Args ...)>() const [with R = void; Args = {std::function<void(std::vector<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > >&&)>}; Actions = {testing::PolymorphicAction<testing::internal::ReturnVoidAction>, testing::internal::InvokeArgumentAction<0, std::vector<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > > >}]'
<source>:33:18:   required from here
/opt/compiler-explorer/gcc-11.2.0/include/c++/11.2.0/tuple:1360:25: error: static assertion failed: tuple index must be in range
 1360 |       static_assert(__i < tuple_size<tuple<>>::value,
      |                     ~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~
/opt/compiler-explorer/gcc-11.2.0/include/c++/11.2.0/tuple:1360:25: note: '(0 < ((long unsigned int)std::integral_constant<long unsigned int, 0>::value))' evaluates to false
In file included from /opt/compiler-explorer/libs/googletest/trunk/googlemock/include/gmock/gmock.h:57,
                 from <source>:2:
/opt/compiler-explorer/libs/googletest/trunk/googlemock/include/gmock/gmock-actions.h: In instantiation of 'testing::internal::DoAllAction<Actions>::operator testing::Action<R(Args ...)>() const [with R = void; Args = {std::function<void(std::vector<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > >&&)>}; Actions = {testing::PolymorphicAction<testing::internal::ReturnVoidAction>, testing::internal::InvokeArgumentAction<0, std::vector<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > > >}]':
<source>:33:18:   required from here
/opt/compiler-explorer/libs/googletest/trunk/googlemock/include/gmock/gmock-actions.h:1061:56: error: could not convert 'std::get<1, testing::PolymorphicAction<testing::internal::ReturnVoidAction>, testing::internal::InvokeArgumentAction<0, std::vector<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > > > >(((const testing::internal::DoAllAction<testing::PolymorphicAction<testing::internal::ReturnVoidAction>, testing::internal::InvokeArgumentAction<0, std::vector<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > > > >*)this)->testing::internal::DoAllAction<testing::PolymorphicAction<testing::internal::ReturnVoidAction>, testing::internal::InvokeArgumentAction<0, std::vector<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > > > >::actions)' from 'std::__tuple_element_t<1, std::tuple<testing::PolymorphicAction<testing::internal::ReturnVoidAction>, testing::internal::InvokeArgumentAction<0, std::vector<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > > > > >' {aka 'const testing::internal::InvokeArgumentAction<0, std::vector<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > > >'} to 'testing::Action<void(std::function<void(std::vector<std::__cxx11::basic_string<char> >&&)>)>'
 1061 |               std::get<sizeof...(Actions) - 1>(actions)};
      |                                                        ^
      |                                                        |
      |                                                        std::__tuple_element_t<1, std::tuple<testing::PolymorphicAction<testing::internal::ReturnVoidAction>, testing::internal::InvokeArgumentAction<0, std::vector<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > > > > > {aka const testing::internal::InvokeArgumentAction<0, std::vector<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > > >}
Execution build compiler returned: 1

如果我删除 && 并将函数的参数从右值引用更改为副本,它可以正常编译。这里会发生什么?

似乎无法使用 r-value 引用。解决方法:

EXPECT_CALL(myService, bar(testing::_)).WillOnce(
    testing::WithArg<0>(
        [] (std::function<void (std::vector<std::string>&&)> f) {
            f({"hello", "world"});
        }
    )

由于某些原因,相关问题已关闭 Add support for move only parameters in mocked methods