2016-04-07 6 views
14

Der folgende Code kompiliert und ausgeführt:Warum verhalten sich `initializer_list <pair>` und `initializer_list <tuple>` anders?

#include <initializer_list> 
#include <iostream> 
#include <vector> 
#include <tuple> 

void ext(std::initializer_list<std::pair<double, std::vector<double> >> myList) 
{ 
    //Do something 
} 

/////////////////////////////////////////////////////////// 

int main(void) { 
    ext({ {1.0, {2.0, 3.0, 4.0} } }); 
    return 0; 
} 

Während dies eine nicht:

#include <initializer_list> 
#include <iostream> 
#include <vector> 
#include <tuple> 

void ext(std::initializer_list<std::tuple<double, std::vector<double> >> myList) 
{ 
    //Do something 
} 

/////////////////////////////////////////////////////////// 

int main(void) { 
    ext({ {1.0, {2.0, 3.0, 4.0} } }); 
    return 0; 
} 

Der einzige Unterschied besteht darin, dass im ersten Fall die ext() Funktion ein Argument vom Typ initializer_list<pair> (Werken) nimmt während der andere initializer_list<tuple> verwendet (funktioniert nicht). cplusplus.com states that

Paare sind ein besonderer Fall von Tupel.

Warum funktioniert der eine Code und der andere nicht?


Zusätzliche Informationen

der Fehler durch Klirren ++ im zweiten Fall ausgegeben ist:

main.cpp:33:2: error: no matching function for call to 'ext' 
     ext({ {1.0, {2.0, 3.0, 4.0} } }); 
     ^~~ 
main.cpp:7:6: note: candidate function not viable: cannot convert initializer list argument to 'std::tuple<double, 
     std::vector<double, std::allocator<double> > >' 
void ext(std::initializer_list<std::tuple<double, std::vector<double> >> myList) 
    ^
1 error generated. 

während g ++ Ausgänge:

main.cpp: In function ‘int main()’: 
main.cpp:33:35: error: converting to ‘std::tuple<double, std::vector<double, std::allocator<double> > >’ from initializer list would use explicit constructor ‘constexpr std::tuple<_T1, _T2>::tuple(const _T1&, const _T2&) [with _T1 = double; _T2 = std::vector<double>]’ 
    ext({ {1.0, {2.0, 3.0, 4.0} } }); 
           ^

Antwort

14

cplusplus.com ist kein sehr guter Site, weil es voller falscher Aussage wie "Paare sind ein besonderer Fall von Tupel." Sie könnten stattdessen cppreference verwenden. Tatsächlich ist das Paar kein besonderer Fall von Tupel.

Es wird jetzt in Betracht gezogen, dass tuple das bessere Design ist; pair ist ziemlich viel älter und kann wegen der Abwärtskompatibilität nicht geändert werden.

Die Fehlermeldung zeigt an, dass der Unterschied darin besteht, dass tuple einen explicit-Konstruktor hat, aber pair nicht.

Das heißt, Sie müssen die Klassennamen erwähnen, wenn ein Tupel Konstruktion:

ext({ std::tuple<double,std::vector<double>>{1.0, {2.0, 3.0, 4.0} } }); 

Dies wird C++ 17 wird geändert in: der Konstruktor von tuple explizit sein wird, wenn und nur wenn man der Tupel-Typen ist der Klassen-Typ mit explizitem Konstruktor. gcc 6 implementiert diese Funktion bereits. (Kredit - Jonathan Wakely). Siehe N4387

+4

N.B. Die explizite Bedeutung des Tuple-Konstruktors hängt nun von den Argumenttypen ab, und der Beispielcode ist in C++ 17 gültig (und wird heute mit GCC 6 kompiliert). –

+0

@ JonathanWakely danke für diese Info. Ich fragte mich nur, wie ich antworten würde, wenn OP fragte: "Warum ist es explizit, das scheint nervig" und ich hatte keine gute Antwort –

+0

@ M.M Danke für Ihre Hilfe! In der Tat, das wäre eine gute Frage ... –