2010-11-28 8 views
17

Tenir compte le code suivant:C++ 11 vecteur push_back ambigu

#include <vector> 

struct S { int a; double b; }; 

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

g ++ 4.4 se plaint que l'appel à push_back() est ambigu:

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>] 

Est-ce censé être ambigu selon le standard, ou est-ce juste un problème avec g ++?

Je sais qu'il peut être résolu en écrivant dans le type de S explicitement:

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

mais le nom du type de S peut être long, donc je préfère ne pas le faire ...

+0

Je suppose que votre compilateur n'a pas toutes les nouvelles implémentations de référence rvalue (move ou &&) terminées et un jeu de règles sur lequel le formulaire à utiliser pour ce temporaire (devrait prendre le mobile puisque votre objet est temporaire) – David

Répondre

4

Avec le brouillon le plus récent (n3225), votre code est en fait ambigu. Les candidats qui sont dans le vecteur seront

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

La question est: Est-ce une liste -initialisation d'une const S& une séquence de conversion mieux/pire qu'une liste-initialisation d'un S&&? La résolution de surcharge fera les deux conversions séquences de conversion définies par l'utilisateur. Cela signifie qu'ils sont pas comparable parce qu'il n'y a pas de règle qui peut le faire. Ce numéro est géré par core issue #1079. Si ce problème est accepté, l'intention est que votre code appelle le deuxième candidat. Incidemment, Jason Merril est un développeur GCC :)

6

Est-ce que S doit être un POD? Sinon, définissez un constructeur, et cela devrait fonctionner.

struct S 
{ 
    int a; 
    double b; 

public: 

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

En outre, v.push_back({3, 4.5}) est probablement moins efficace que v.emplace_back(3, 4.5).


Mise à jour: Ça sent comme un bug du compilateur. Cela fonctionne parfaitement avec g ++ 4.6.0 20101025 (expérimental).

+3

Bien utile, pas vraiment ce que demande le PO? Je suis également curieux de savoir ce qui se passe là-bas - pourquoi une variante est ambigus d'être une lvalue/rvalue et l'autre n'est pas, alors qu'ils sont tous les deux, bien, temporaires. – Kos

+2

@Kos: Les temporaires sont de types différents. '{3, 4.5}' est un 'std :: initializer_list ', alors que 'S {3, 4.5}' est un 'S'. Peut-être que cela a à voir avec le fait que «a» est un «int» et non un «double»? Honnêtement, je ne sais pas. – fredoverflow

+0

Intéressant, je ne connaissais pas emplace_back. Cependant, il semble aussi avoir besoin d'un constructeur pour S. – HighCommander4