compiler - c++14
¿Por qué no se pudo sobrecargar push_back para hacer el trabajo de emplace_back? (2)
Aquí hay otro ejemplo.
Honestamente, los dos son semánticamente tan diferentes, que su comportamiento similar debe considerarse como una mera coincidencia (debido al hecho de que C ++ tiene "constructores de copia" con una sintaxis particular).
Realmente no emplace_back
usar emplace_back
menos que quieras una semántica de construcción en el lugar .
Es raro que necesites tal cosa. Generalmente push_back
es lo que realmente quieres, semánticamente.
#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 &)
}
En primer lugar, soy consciente de esta pregunta , pero no creo que esté preguntando lo mismo.
Sé lo que hace std::vector<T>::emplace_back
, y entiendo por qué lo usaría sobre push_back()
. Utiliza plantillas variadic que me permiten enviar múltiples argumentos al constructor de un nuevo elemento.
Pero lo que no entiendo es por qué el comité estándar de C ++ decidió que era necesaria una nueva función de miembro. ¿Por qué no podrían simplemente extender la funcionalidad de push_back()
. Por lo que puedo ver, push_back
podría estar sobrecargado en C ++ 11 para ser:
template <class... Args>
void push_back(Args&&... args);
Esto no rompería la compatibilidad hacia atrás, mientras que le permite pasar N argumentos, incluidos los argumentos que invocarían un valor normal o un constructor de copia. De hecho, la implementación de GCC C ++ 11 de push_back()
simplemente llama a emplace_back de todos modos:
void push_back(value_type&& __x)
{
emplace_back(std::move(__x));
}
Entonces, tal como lo veo, no hay necesidad de emplace_back()
. Todo lo que necesitaban para agregar era una sobrecarga para push_back()
que acepta argumentos variadic y reenvía los argumentos al constructor del elemento.
¿Estoy equivocado aquí? ¿Hay alguna razón para que una función completamente nueva fuera necesaria aquí?
Si T tiene un constructor de conversión explícito, hay un comportamiento diferente entre emplace_back
y 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
}
Hacer el cambio que sugieres significaría que push_back
sería legal en esa instancia, y supongo que ese no fue el comportamiento deseado. No sé si esta es la razón, pero es lo único que se me ocurre.