The following code fails for push_back
and succeeds for 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&)'
}
I understand that push_back
failes because it takes a reference and tries to cast away volatile
qualifier implicitly from that reference.
However, emplace_back
also takes a reference (rvalue-references are references). Why is it treated differently?
That is because of how they are defined in the C++11 Standard. Paragraph 23.3.6.1 specifies their signature:
template <class... Args> void emplace_back(Args&&... args);
void push_back(const T& x);
void push_back(T&& x);
While the parameters of the available overloads of push_back()
do not have any volatile
qualification, the argument of the emplace_back()
function template can bind to lvalues with any cv
-qualification.
However, emplace_back also takes a reference (rvalue-references are references). Why is it ttreated differently?
Yes, because emplace_back()
is a function template, and type deduction will infer Args
to be an argument pack of length one, whose only element has type int volatile&
(see Paragraph 14.8.2.1/3).
The overloads of push_back()
, on the other hand, are regular member functions of the std::vector<>
class template, and there is no type deduction going on when invoking them. Since references to non-volatile
cannot bind to objects qualified as volatile
(see Paragraph 8.5.3/4-5), the compiler won't be able to resolve the call.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With