2017-01-06 1 views
57

Warum sind die ersten beiden Aufrufe an doSomething OK vom Compiler, aber die Verwendung von zwei Elementen in der Liste verursacht einen mehrdeutigen Aufruf?Warum verursacht die Anzahl der Elemente in einer Initialisierungsliste einen mehrdeutigen Aufruffehler?

#include <vector> 
#include <string> 

void doSomething(const std::vector<std::string>& data) {} 

void doSomething(const std::vector<int>& data) {} 

int main(int argc, char *argv[]) 
{ 
    doSomething({"hello"}); // OK 
    doSomething({"hello", "stack", "overflow"}); // OK 
    doSomething({"hello", "stack"}); // C2668 'doSomething': ambiguous call 

    return 0; 
} 

Antwort

56

Was hier passiert, ist, dass in der Zwei-Element-Initialisiererliste beide String-Literale implizit in const char* konvertiert werden können, da ihr Typ const char[N] ist. Jetzt hat std::vector einen Konstruktor, der zwei Iteratoren benötigt, für die sich die Zeiger qualifizieren. Aus diesem Grund steht der initializer_list-Konstruktor von im Konflikt mit dem Iterator-Bereichskonstruktor std::vector<int>.

Wenn wir den Code stattdessen ändern

doSomething({"hello"s, "stack"s}); 

werden dann die Elemente der Initialisiererliste sind jetzt std::string s so keine Zweideutigkeit gibt.

+6

Oder 'DoSomething (Std :: Vektor ({" Hallo "," Stack "}));', aber Ihre Lösung ist lesbarer. In jedem Fall, wenn es sich um echten Code handelt, würde ich wahrscheinlich auch einen kleinen Kommentar hinzufügen, um die scheinbar nutzlose Deutlichkeit zu erklären. –

+0

Ich dachte der Konstruktor initialiser_list wird immer aufgerufen, wenn möglich, zum Beispiel in std :: vector {5,1} man bekommt einen Vektor mit Elementen 5 und 1 und nicht 5 mal 1. Warum ist das hier nicht der Fall? –

+0

@ ab.o2c Der Konstruktor der Initialisierungsliste wird bevorzugt, aber wir haben in diesem Fall nicht 'std :: vector {5,1}'. Was wir haben, ist 'std :: vector {const char *, const char *}'. Da die Initialisiererliste den gleichen Typ wie die Elemente des Vektors haben muss, wird sie in diesem Fall ignoriert und der Iteratorkonstruktor wird ausgewählt. – NathanOliver

23

Sowohl die einargumentigen und drei Argument Listen können nur std::vector<std::string> ‚s std::initializer_list Konstruktor entsprechen. Allerdings entspricht die zweiArgumentListe einer der Konstrukteure von std::vector<int>:

template <class InputIt> 
vector(InputIt first, InputIt last, Allocator const &alloc = Allocator()); 

der Tat kann ein char const * erhöht werden, und dereferenziert einen char zu erhalten, die implizit konvertierbar zu einem int ist.

16

"hello" und "stack" beide zerfallen zu const char *, die das InputIterator Konzept erfüllt. Dadurch können sie std::vector's constructor #4 entsprechen.

Wenn Sie std::string Objekte übergeben, ist die Mehrdeutigkeit behoben.

Verwandte Themen