Bedenken Sie Folgendes:
%Vor% Ich wollte, dass das Ergebnis ein Programm ist, das bei der Ausführung d
ausgibt.
Stattdessen bekomme ich das :
%Vor%(ähnliche Ergebnisse unter GCC)
Wie kann ich das beheben?
Ich bekomme einen ähnlichen Fehler, auch wenn ich std::map<int, char>(map_list_of(...))
anstelle von map_list_of(...)
für diese inneren Karten verwende.
C ++ 03 definiert zwei Konstruktoren für map
, die mit einem Argument [lib.map] p2:
%Vor%
boost's map_list_of
erzeugt ein Objekt einer generic_list
-Klassenvorlageninstanz aus dem letzten SVN:
%Vor%
Wo die primäre generic_list
Vorlage den folgenden Konvertierungsoperator enthält:
%Vor%
Beide Konstruktoren map
sind praktikabel, da dieser Operator die Konvertierung sowohl in map
als auch in Compare
erlaubt. Soweit ich weiß, kann man in C ++ 03 keinen Conversion-Operator mit SFINAE einschränken.
Das map
wird explizit konstruiert, wenn ein neuer Knoten in die äußere Karte eingefügt wird. Ein Paar Iteratoren wird verwendet, um über die innere generic_list
zu iterieren, um die äußere map
zu konstruieren. Die Dereferenzierung dieses Iterators ergibt std::pair<int, boost::assign_detail::generic_list<std::pair<int, char> >
. Der Knoten (Wert) Typ der äußeren Karte ist std::pair<int const, std::map<int, char> >
.
Daher versucht der Compiler, den letzteren Typ aus dem ersteren zu konstruieren. In C ++ 03 ist dieser pair
-Konstruktor nicht SFINAE-eingeschränkt, da dies in C ++ 03 nicht möglich ist. [lib.pairs] p1
%Vor%
libstdc ++ implementiert dies wie folgt:
%Vor%Ich bin mir nicht ganz sicher, ob das konform ist, seit [lib.pairs] p4
Effekte: Initialisiert Member aus den entsprechenden Membern des Arguments und führt bei Bedarf implizite Konvertierungen durch.
(Aber wie gesagt, SFINAE auf ctors kann nicht in C ++ 03 implementiert werden.)
In C ++ 11 und 14 schlägt dies ebenfalls fehl, aber aus einem anderen Grund. Hier sind die Paarkonstruktoren SFINAE-beschränkt. Die Einschränkung erfordert jedoch implizite Konvertierbarkeit ( is_convertible
), während das Programm UB hat, wenn das Zielpaar der Typen nicht aus den Quellen konstruiert werden kann ( is_constructible
). Ich habe ein bisschen mehr zu diesem Thema in eine weitere SO-Antwort geschrieben. Interessanterweise ist eine vorgeschlagene Lösung N4387 zu dem darin genannten Thema andere Frage sagt:
Es sollte hier bemerkt werden, dass für den allgemeinen Fall der
std::is_constructible<T, U>::value
Anforderung für das nicht explizite Konstruktor, der aufstd::is_convertible<U, T>::value
beschränkt ist ist nicht redundant, weil es möglich ist, Typen zu erstellen, die sein können kopierinitialisiert, aber nicht direkt initialisiert
Dies ist genau der Fall, dem wir hier begegnen: Ein map
kann von einem generic_list
kopierinitialisiert werden, da dies den explicit
-Konstruktor nicht lebensfähig macht. Aber ein map
kann nicht direkt von generic_list
initialisiert werden, da dies die Konvertierung mehrdeutig macht.
Soweit ich sehen kann, löst N4387 das Problem im OP nicht. Auf der anderen Seite haben wir mit einer einheitlichen Initialisierung eine Alternative zu map_list_of
. Und wir können SFINAE Conversion-Operatoren seit C ++ 11 einschränken.
Eine Lösung besteht darin, den Konstruktor explicit
zu eliminieren, indem nur implizite Konvertierungen zugelassen werden:
Aber es gibt einen direkteren Weg: Verwenden Sie einfach die convert_to_container
-Memberfunktion von generic_list
's Basisklasse converter
(auch eine Klassenvorlage):