将左值传递给用作临时标准容器的模板参数的通用引用参数时与分配器相关的错误

Allocator-related error when passing lvalue to a universal reference parameter that is used as template parameter to a temporary std container

我已将我的用例简化为一个最小的无意义示例:

#include <vector>

template<typename Container>
void f(Container&) { // using && gives compilation error... (*)
    std::vector<Container>{};
};

int main() {
    std::vector<int> v;
    f(v); // (*) ... which is "solved" by std::move-ing v here. Why?
}

编译。但是,当我添加另一个 & 以使未命名参数成为转发引用时,出现以下错误(使用 g++ -std=c++11 thatfile.cpp-std=c++17 编译)。另一方面,在呼叫站点 std::moveing v 解决了问题。

我想知道为什么。

In file included from /usr/include/c++/10.2.0/x86_64-pc-linux-gnu/bits/c++allocator.h:33,
                 from /usr/include/c++/10.2.0/bits/allocator.h:46,
                 from /usr/include/c++/10.2.0/vector:64,
                 from prova.cpp:1:
/usr/include/c++/10.2.0/ext/new_allocator.h: In instantiation of ‘class __gnu_cxx::new_allocator<std::vector<int>&>’:
/usr/include/c++/10.2.0/bits/allocator.h:116:11:   required from ‘class std::allocator<std::vector<int>&>’
/usr/include/c++/10.2.0/bits/stl_vector.h:87:21:   required from ‘struct std::_Vector_base<std::vector<int>&, std::allocator<std::vector<int>&> >’
/usr/include/c++/10.2.0/bits/stl_vector.h:389:11:   required from ‘class std::vector<std::vector<int>&, std::allocator<std::vector<int>&> >’
prova.cpp:5:5:   required from ‘void f(Container&&) [with Container = std::vector<int>&]’
prova.cpp:10:8:   required from here
/usr/include/c++/10.2.0/ext/new_allocator.h:62:26: error: forming pointer to reference type ‘std::vector<int>&’
   62 |       typedef _Tp*       pointer;
      |                          ^~~~~~~
/usr/include/c++/10.2.0/ext/new_allocator.h:63:26: error: forming pointer to reference type ‘std::vector<int>&’
   63 |       typedef const _Tp* const_pointer;
      |                          ^~~~~~~~~~~~~
/usr/include/c++/10.2.0/ext/new_allocator.h:103:7: error: forming pointer to reference type ‘std::vector<int>&’
  103 |       allocate(size_type __n, const void* = static_cast<const void*>(0))
      |       ^~~~~~~~
/usr/include/c++/10.2.0/ext/new_allocator.h:120:7: error: forming pointer to reference type ‘std::vector<int>&’
  120 |       deallocate(_Tp* __p, size_type __t)
      |       ^~~~~~~~~~

...

当你有

template<typename Container>
void f(Container&) { // using && gives compilation error... (*)
    std::vector<Container>{};
};

Constainer 被推导为 std::vector,一切正常。当你使用

template<typename Container>
void f(Container&&) { // using && gives compilation error... (*)
    std::vector<Container>{};
};

而你不使用std::move,则Container推导为std::vector&,是引用类型,不能创建引用类型的vector,所以你得到一个错误。

当您使用 std::move(v) 时,您将 std::vector&& 传递给函数,因此 Container 再次被推断为 std::vector 并且代码编译,因为它不是参考类型。