Warum nehmen Vektor Konstruktoren mit mehreren Argumenten Konstruktionsparameter an, die nicht explizit markiert sind?

9

Ich beobachtete die folgenden Vektorkonstruktoren in der Standard-C ++ - Bibliothek

%Vor%

Gibt es einen Grund, warum der zweite Konstruktor nicht als explicit markiert ist? Das kompiliert und macht mich schlecht fühlen

%Vor%

Wenn ich das "foo" weglasse, kompiliert es nicht, und das erwarte ich, wenn ich einen Paar (zusammengesetzten) Wert eines int und eines Strings an eine Funktion übergebe, die einen Vektor von Strings haben will.

    
Johannes Schaub - litb 02.02.2013, 17:29
quelle

3 Antworten

3

Ich frage mich, ob es in erster Linie legitim ist zu erwarten, dass { ... } immer eine Liste von Containerelementen darstellt, wenn ein temporäres erstellt wird. Dies scheint deine Annahme zu sein. IMO der Einargumentkonstruktor muss als explicit deklariert werden, um unerwünschte Konvertierungssequenzen oder bedeutungslose Zuweisungen wie:

zu vermeiden %Vor%

Andererseits kann dieser Konstruktor für die Zwei-Argument-Version, wenn ein Temporär erstellt wird, mit der Verwendung geschweifter Klammern aufgerufen werden, was dem Programmierer bekannt ist was er da reinlegt. Zum Beispiel ist es für mich ziemlich klar, dass 10 und "hello" nicht dazu gedacht sind, eine Liste von Containerelementen darzustellen, weil 10 keine Zeichenkette ist.

Wenn ich wirklich einen Vektor von 10 Elementen übergeben wollte, die auf "hello" initialisiert wurden, würde es mich stören, wenn ich f(vector(10, "hello")) schreiben müsste anstatt nur f({10, "hello"}) .

Also, um es zusammenzufassen: Während der Konstruktor mit einem Argument als explicit deklariert werden muss, glaube ich, dass dies für den Zwei-Argument-Wert nicht obligatorisch ist, weil nicht alles, was in einem Paar geschweifter Klammern ist, sein sollte interpretiert als eine Liste von Containerelementen.

    
Andy Prowl 02.02.2013 18:06
quelle
1
  

Wenn ich das "foo" weglasse, kompiliert es nicht und das ist, was ich erwarte   wenn ich einen Paar (zusammengesetzten) Wert eines int und eines Strings an eine Funktion übergebe, die will   ein Vektor von Strings.

Nein, Sie übergeben kein Paar int und eine Zeichenfolge, sondern Sie erstellen einen Vektor der Größe 10 mit dem Inhalt von Strings wie "foo". Da ist nichts falsch daran! Ich kann eine Situation darstellen, in der es nützlich sein kann, einen Vektor zu erstellen, der die gleichen Strings von Anfang an enthält.

    
duDE 02.02.2013 17:43
quelle
0
  

das erwarte ich, wenn ich einen Paar (zusammengesetzten) Wert eines int und eines Strings an eine Funktion übergebe, die einen Vektor von Strings haben will.

Nun, da ist dein Problem.

{...} ist kein "zusammengesetzter Wert". Es ist keine Liste. Es heißt "initialisiere ein Objekt mit diesen Werten". Wenn das fragliche Objekt ein Aggregat ist, verwendet es die Aggregat-Initialisierung. Wenn es sich bei dem Objekt um einen nicht aggregierten Typ handelt, wird ein aufzurufender Konstruktor ausgewählt, basierend auf den übereinstimmenden Konstruktoren des Typs und den verschiedenen Regeln für stacked-init-Listen in C ++ 11.

Sie sollten nicht an {10, "foo"} als Liste von zwei Werten denken. Es ist ein Initialisierer, der zwei Werte enthält. Es könnte mit std::pair<int, const char *> und so weiter verwendet werden.

Der Grund, warum der Konstruktor von std::vector nicht explizit ist, ist genau erlaubt dieses Konstrukt. Der Konstruktor mit einem Argument ist explizit, da andernfalls implizite Konvertierungsregeln dies zulassen würden:

%Vor%

Oder, was noch wichtiger ist:

%Vor%

Wir möchten nicht, dass ganze Zahlen implizit in std::vector s umgewandelt werden können. Wenn Sie jedoch einen Initialisierer verwenden, ist es sinnvoller, einen größeren Bereich von "impliziten" Konvertierungen zuzulassen, da Sie die {} -Syntax dort sehen können.

Bei dem Fall mit einem Argument ist nicht klar, was der Benutzer meint. Mit der Syntax {} ist klar, was der Benutzer meint: um das Objekt zu initialisieren.

%Vor%     
Nicol Bolas 02.02.2013 20:47
quelle