Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

push_back vs emplace_back with a volatile

Tags:

c++

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?

like image 748
StackedCrooked Avatar asked Feb 16 '23 22:02

StackedCrooked


1 Answers

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.

like image 142
Andy Prowl Avatar answered Feb 28 '23 15:02

Andy Prowl