2016-05-04 5 views
22

Der folgende CodeMögliche Regression in G ++ 6.1.0

#include <string> 
#include <map> 
#include <cassert> 

    struct  AV { 
     explicit AV(std::string const&) {} 
    }; 

#if 1 
    static void check_cache_item(
     std::map<std::string, std::string> const& items) // FIXME remove 
    { 
     assert(!items.empty()); 
    } 
#endif 
    static void check_cache_item(
     std::map<std::string, AV> const& items) 
    { 
     assert(!items.empty()); 
    } 


int main() 
{ 
    check_cache_item({ { "id", "0" }, { "pk", "#0" } }); 
    check_cache_item({ { "id", "0" }, { "pk", "#1" } }); 
    check_cache_item({ { "id", AV{"0"} }, { "pk", AV{"#1"} } }); 
} 

durch g angenommen wird ++ 4.8.4, 5.3.0 g ++, klappern ++ 3.9.0; aber g ++ 6.1.0 gibt einen Fehler:

cci.cc: In function ‘int main()’: 
cci.cc:25:55: error: call of overloaded ‘check_cache_item(<brace-enclosed initializer list>)’ is ambiguous 
    check_cache_item({ { "id", "0" }, { "pk", "#0" } }); 
                ^
cci.cc:10:17: note: candidate: void check_cache_item(const std::map<std::__cxx11::basic_string<char>, std::__cxx11::basic_string<char> >&) 
    static void check_cache_item(
       ^~~~~~~~~~~~~~~~ 
cci.cc:16:17: note: candidate: void check_cache_item(const std::map<std::__cxx11::basic_string<char>, AV>&) 
    static void check_cache_item(
       ^~~~~~~~~~~~~~~~ 
cci.cc:26:55: error: call of overloaded ‘check_cache_item(<brace-enclosed initializer list>)’ is ambiguous 
    check_cache_item({ { "id", "0" }, { "pk", "#1" } }); 
                ^
cci.cc:10:17: note: candidate: void check_cache_item(const std::map<std::__cxx11::basic_string<char>, std::__cxx11::basic_string<char> >&) 
    static void check_cache_item(
       ^~~~~~~~~~~~~~~~ 
cci.cc:16:17: note: candidate: void check_cache_item(const std::map<std::__cxx11::basic_string<char>, AV>&) 
    static void check_cache_item(
       ^~~~~~~~~~~~~~~~ 
cci.cc: At global scope: 
cci.cc:10:17: warning: ‘void check_cache_item(const std::map<std::__cxx11::basic_string<char>, std::__cxx11::basic_string<char> >&)’ defined but not used [-Wunused-function] 
    static void check_cache_item(
       ^~~~~~~~~~~~~~~~ 

Wenn ich den ersten Konstruktor #IFDEF, dann jeder Compiler einen Fehler wirft (zu Recht, da der AV-Konstruktor explizit).

Ist das eine Regression in G ++ 6.1.0?

+1

[Online Repro Beispiel] (http://melpon.org/wandbox/permlink/0Z1d2KR6anWldz7o) –

+0

G ++ 7 (Stamm) berichtet, auch ein Fehler – Bulletmagnet

Antwort

14

Dies ist ein überraschender und etwas unglücklicher Aspekt des Standards (ich würde so weit gehen, es als einen Defekt zu bezeichnen); es ist das Ergebnis einer Kollision zwischen den Überladungsauflösungsregeln für die Kopierlisteninitialisierung ([over.match.list] wie in CWG 1228 bestätigt) und dem Elementweiterleitungskonstruktor von pair (gemäß n4387).

gcc (> = 6.1.0) ist richtig, um Ihr Programm abzulehnen; Clang ist falsch, es zu akzeptieren. Frühere Versionen von gcc akzeptieren Ihr Programm, weil sie n4387 noch nicht implementiert haben; Klirren akzeptiert Ihr Programm, weil es excludes explicit constructors from consideration for overload resolution for copy-list-initialization, die [over.match.list] nach der Norm (Calling an explicit constructor with a braced-init list: ambiguous or not?)


verletzt Wenn wir die Fremd Aspekte Ihres Programms kommt es auf eine einfache Frage abzulösen Überlastung Auflösung:

struct A { explicit A(int, int); }; 
struct B { B(int, int); }; 

void f(A); 
void f(B); 

int main() { f({0, 0}); } 

Hier A steht in für pair<std::string const, AV> und B steht für pair<string const, string> in. Der Konstruktor A ist explizit, weil Schritt n4387 den expliziten Konstruktor AV betrifft; aber pro CWG 1228 die Regeln für die Kopie-list-Initialisierung:

[...] include all constructors but state that the program is ill-formed if an explicit constructor is selected by overload resolution. [...]

[over.match.list]:

[...] In copy-list-initialization, if an explicit constructor is chosen, the initialization is ill-formed. [ Note: This differs from other situations ([over.match.ctor], [over.match.copy]), where only converting constructors are considered for copy-initialization. This restriction only applies if this initialization is part of the final result of overload resolution. — end note ]

So kann Ihr Programm korrekt betrachtet wird (unter der Norm, wie es derzeit ist) sein zweideutig.

Weiterführende Literatur: What could go wrong if copy-list-initialization allowed explicit constructors?

+2

ich nicht sicher bin, ist notwendigerweise ein Defekt, obwohl es etwas überraschend ist. –

+2

"implementiert CWG 1228 nicht" Was ist dort zu implementieren? Ich dachte das Ergebnis von CWG ist, dass die im Standard geschriebenen Regeln korrekt sind. Es gibt keine vorgeschlagene Änderung, oder? – Barry

+0

@ T.C. Gut, aber ich behalte mir das Recht vor, es selbst als Defekt zu betrachten. – ecatmur