Push_back与emplace_back的易失性

push_back vs emplace_back with a volatile

本文关键字:back 易失性 Push emplace      更新时间:2023-10-16

push_back失败,emplace_back成功:

#include <vector>
volatile int x = 0;
int main()
{        
    std::vector<int> vec;
    vec.emplace_back(x);
    vec.push_back(x); // error: no matching function for call to 'std::vector<int>::push_back(volatile int&)'
}

我理解push_back失败是因为它接受了一个引用,并试图从该引用中隐式地抛弃volatile限定符。

但是,emplace_back 也接受引用(右值引用就是引用)。为什么会有不同的待遇?

这是因为它们在c++ 11标准中的定义方式。第23.3.6.1段规定了它们的签名:

template <class... Args> void emplace_back(Args&&... args);
void push_back(const T& x);
void push_back(T&& x);

虽然push_back()的可用重载的形参没有任何volatile限定,但emplace_back()函数模板的实参可以绑定到具有任何cv限定的左值。

然而,emplace_back也接受一个引用(右值引用就是引用)。为什么会有不同的待遇?

是的,因为emplace_back()是一个函数模板,并且类型推导将Args推断为长度为1的参数包,其唯一的元素类型为int volatile&(参见第14.8.2.1/3段)。

另一方面,push_back()的重载是std::vector<>类模板的常规成员函数,在调用它们时不进行类型演绎。由于对非volatile的引用不能绑定到限定为volatile的对象(参见第8.5.3/4-5段),编译器将无法解析调用。