Почему нельзя было перегружать push_back для выполнения задания emplace_back?
Во-первых, я знаю этот вопрос, но я не верю, что я прошу то же самое.
Я знаю, что делает std::vector<T>::emplace_back
, и я понимаю, почему я буду использовать его поверх push_back()
. Он использует вариационные шаблоны, позволяющие мне пересылать несколько аргументов конструктору нового элемента.
Но я не понимаю, почему комитет по стандарту С++ решил, что существует потребность в новой функции-члене. Почему они не могут просто расширить функциональность push_back()
. Насколько я вижу, push_back
может быть перегружен в С++ 11:
template <class... Args>
void push_back(Args&&... args);
Это не нарушит совместимость в обратном направлении, позволяя вам передавать N аргументов, включая аргументы, которые будут вызывать обычный конструктор rvalue или copy. Фактически реализация GCC С++ 11 push_back()
просто вызывает emplace_back:
void push_back(value_type&& __x)
{
emplace_back(std::move(__x));
}
Итак, как я его вижу, нет необходимости в emplace_back()
. Все, что им нужно было добавить, это перегрузка для push_back()
, которая принимает вариационные аргументы и пересылает аргументы конструктору элемента.
Я здесь не прав? Есть ли какая-то причина, что здесь нужна совершенно новая функция?
Ответы
Ответ 1
Если T имеет явный конструктор преобразования, между emplace_back
и push_back
существует другое поведение.
struct X
{
int val;
X() :val() {}
explicit X(int v) :val(v) {}
};
int main()
{
std::vector<X> v;
v.push_back(123); // this fails
v.emplace_back(123); // this is okay
}
Выполнение предложенного вами изменения означает, что push_back
будет законным в этом случае, и я полагаю, что это нежелательное поведение. Я не знаю, является ли это причиной, но это единственное, что я могу придумать.
Ответ 2
Вот еще один пример.
Честно говоря, эти два семантически отличаются друг от друга, что их сходное поведение следует рассматривать как простое совпадение (из-за того, что С++ имеет "конструкторы копирования" с определенным синтаксисом).
Вы действительно не должны использовать emplace_back
, если вы не хотите использовать семантику на месте.
Редко, что вам нужно такое. Обычно push_back
- это то, что вы действительно, семантически хотите.
#include <vector>
struct X { X(struct Y const &); };
struct Y { Y(int const &); operator X(); };
int main()
{
std::vector<X> v;
v. push_back(Y(123)); // Calls Y::operator X() and Y::Y(int const &)
v.emplace_back(Y(123)); // Calls X::X(Y const &) and Y::Y(int const &)
}