2010-11-28 25 views
17

Considere el siguiente código:C++ 11 vector push_back ambigua

#include <vector> 

struct S { int a; double b; }; 

int main() 
{ 
    std::vector<S> v; 
    v.push_back({3, 4.5}); 
} 

g ++ 4.4 se queja de que la llamada a push_back() es ambigua:

error: call of overloaded ‘push_back(<brace-enclosed initializer list>)’ is ambiguous 
note: candidates are: void std::vector<_Tp, _Alloc>::push_back(const _Tp&) [with _Tp = S, _Alloc = std::allocator<S>] 
note:     void std::vector<_Tp, _Alloc>::push_back(_Tp&&) [with _Tp = S, _Alloc = std::allocator<S>] 

Es éste supone que es ambigua según el estándar, o es solo un problema con g ++?

Sé que puede ser resuelto por la escritura en el tipo de forma explícita S:

v.push_back(S{3, 4.5}); 

pero el nombre del tipo de S puede ser largo, así que preferiría no hacerlo ...

+0

Supongo que su compilador no tiene todas las nuevas implementaciones de referencia rvalue (mover o &&) completadas y una regla establecida sobre qué forma prefiere usar para ese temporal (debería tomar el móvil ya que su objeto es temporal) – David

Respuesta

4

Con el borrador más reciente (n3225), su código es de hecho ambiguo. Los candidatos que se encuentran en vector será

void push_back(const S& x); 
void push_back(S&& x); 

La pregunta es: ¿Es un lista de inicialización de un const S& un secuencia de conversión mejor/peor que una lista-inicialización de un S&&? La resolución de sobrecarga hará que ambas conversiones definan las secuencias de conversión. Esto significa que son no comparables porque no hay ninguna regla que pueda hacerlo.

Esto es manejado por core issue #1079. Si se acepta ese problema, la intención es que su código llame al segundo candidato. Por cierto, Jason Merril es un desarrollador de GCC :)

6

¿Tiene que ser S un POD? Si no, defina un constructor, y debería funcionar.

struct S 
{ 
    int a; 
    double b; 

public: 

    S(int a, double b) : a(a), b(b) {} 
}; 

Además, v.push_back({3, 4.5}) es probablemente menos eficiente que v.emplace_back(3, 4.5).


actualización: Huele a un error del compilador. Funciona perfectamente con g ++ 4.6.0 20101025 (experimental).

+3

Aunque es útil, ¿no es realmente lo que pregunta el OP? También siento curiosidad por lo que sucede allí: por qué una variante es ambiciosa acerca de ser un lvalue/rvalue y la otra no, mientras que ambas son, bueno, temporales. – Kos

+2

@Kos: los temporales son de diferentes tipos. '{3, 4.5}' es un 'std :: initializer_list ', mientras que 'S {3, 4.5}' es un 'S'. ¿Tal vez tiene que ver con el hecho de que 'a' es un' int' y no un 'doble'? Honestamente, yo no sé. – fredoverflow

+0

Interesante, no sabía acerca de emplace_back. Sin embargo, también parece requerir un constructor para S. – HighCommander4