阅读标准的this和this以及23.3.6.5/1,其中最新的C ++标准草案规定,实施者应优先使用非投掷移动构造函数{{ 1 {}当T(T &&t) noexcept
由于T(const T &t)
操作重新分配其元素时,在const复制构造函数std::vector<T>
上面?它是13.3.3.1.4/1重载参考绑定的解决方案吗?
编辑1
我在13.3.3.1.4/1争论,原因如下:
重载分辨率选择要在语言中的七个不同上下文中调用的函数。 [...] 调用构造函数以进行类对象的直接初始化(8.5)(13.3.1.3); [...]这些上下文中的每一个都以其自己独特的方式定义候选函数集和参数列表。但是,一旦确定了候选函数和参数列表,最佳函数的选择在所有情况下都是相同的:首先,候选函数的子集(具有适当数量的参数并满足某些其他条件的函数)是选择形成一组可行的功能( 13.3.2 )。然后根据将每个参数与每个可行函数的相应参数匹配所需的隐式转换序列( 13.3.3.1 )来选择最佳可行函数。
从为给定上下文( 13.3.1 )构造的候选函数集中,选择一组可行函数,通过比较参数转换序列,从中选择最佳函数。最适合( 13.3.3 )。可行函数的选择考虑了参数和函数参数之间的关系,而不是转换序列的排名。
当类类型的对象被直接初始化(8.5),或者从相同或派生类类型(8.5)的表达式进行复制初始化时,重载决策选择构造函数
如果参数类型为参考,请参阅 13.3.3.1.4 。
当引用类型的参数直接(8.5.3)绑定到参数表达式时,隐式转换序列为标识转换,[...]
因此,我得出结论,身份转换的要求导致要求push_back
优先于T(T &&t) noexcept
。但是,我所争辩的另一方并不相信。所以,我在这里问。
编辑2
以下是23.3.6.5和13.3.3.1.4之间的链接:
首先,23.3.6.5需要以下T(const T &t)
:
[...]
std::vector
void push_back(const T& x);
备注:[...]如果复制构造函数抛出除之外的异常,移动构造函数,赋值运算符或T的移动赋值运算符,或者通过任何InputIterator操作都有否< / strong>效果。 [...]
由23.3.6.1/2涵盖,需要以下内容:
向量满足所有的容器和可逆容器的要求(在23.2中的两个表中给出),[...]
也就是说,void push_back(T&& x);
应符合指定以下内容的23.2.1/7:
除非另有说明,否则本节中定义的所有容器使用分配器获取内存(参见17.6.3.5)。
和23.2.1/3指定以下内容:
对于受此子条款影响的声明
std::vector
的组件,存储在这些组件中的对象应使用allocator_type
函数构造,并使用allocator_traits&lt; allocator_type&gt;进行销毁。 :: destroy功能( 20.7.8.2 )。这些函数仅针对容器的元素类型调用,而不是针对容器使用的内部类型调用。
由于20.7.8.2仅指定一个allocator_traits<allocator_type>::construct
函数,如下所示:
construct
20.7.8.2/5需要以下内容:
效果:如果调用格式良好,则调用
template <class T, class... Args> static void construct(Alloc& a, T* p, Args&&... args);
;否则,请调用a.construct(p, std::forward<Args>(args)...)
。
和20.7.9.2/12需要以下默认分配器:
效果:
::new (static_cast<void*>(p)) T(std::forward<Args>(args)...)
,20.7.8.2/5中的::new((void *)p) U(std::forward<Args>(args)...)
和20.7.9.2/12中的T(std::forward<Args>(args)...)
都将遵循13.3.3.1.4/1中的构造函数重载决策要求。
因此,当U(std::forward<Args>(args)...)
由于T(T &&t) noexcept
操作重新分配其元素时,标准要求实施者优先使用move-constructor T(const T &t)
而不是copy-constructor std::vector<T>
。