dieses Programm Gegeben:`pair :: operator = (Paar &&)` Fehler mit `auto &` abgeleitete Verschiebeoperationen - libstdC++ Regression?
struct Val
{
Val() = default;
Val(Val&&) = default;
auto& operator=(Val&&);
};
/* PLACEHOLDER */
auto& Val::operator=(Val&&) { return *this; }
/* PLACEHOLDER */
mit ...
int main()
{
std::vector<std::pair<int, Val>> v;
v.emplace(std::begin(v), 0, Val{});
}
... kompiliert erfolgreich auf Substituieren:
- g ++ 6.2.0
- g ++ 6.3.0
g ++ 7.0.1 (Stamm)
Klirren ++ 3.9.1
- Klirren ++ 5.0.0 (HEAD)
Substituieren /* PLACEHOLDER */
mit ...
template <typename TVec>
void a(TVec& v)
{
v.emplace(std::begin(v), 0, Val{});
}
int main()
{
std::vector<std::pair<int, Val>> v;
a(v);
}
... kompiliert erfolgreich auf:
- g ++ 6.2.0
- Klirren ++ 3.9.1
... aber erzeugt einen Fehler bei der Kompilierung auf:
- g ++ 6.3.0
- g ++ 7.0.1 (trunk)
- Klirren ++ 5.0.0 (HEAD)
Der erzeugte Fehler scheint zu einer eingeschränkten pair operator=(pair&&)
Überlastung bezogen werden - from include/bits/stl_pair.h
on GitHub's libstdc++ mirror :
pair&
operator=(typename conditional<
__and_<is_move_assignable<_T1>,
is_move_assignable<_T2>>::value,
pair&&, __nonesuch&&>::type __p)
noexcept(__and_<is_nothrow_move_assignable<_T1>,
is_nothrow_move_assignable<_T2>>::value)
{
first = std::forward<first_type>(__p.first);
second = std::forward<second_type>(__p.second);
return *this;
}
Das Ersetzen von durch
std::true_type
ermöglicht die Kompilierung des Codes.Durch Verschieben der Definition von
Val::operator=(Val&&)
vor/* PLACEHOLDER */
kann der Code kompiliert werden.Durch die Änderung
auto& Val::operator=(Val&&)
zuVal& Val::operator=(Val&&)
kann der Code kompiliert werden.
Was geht hier vor? Ist das ein Implementierungsfehler in der neuesten Version von libstdC++? Oder haben die älteren Versionen schlecht formatierten Code falsch kompiliert?
EDIT: als AndyG in seiner entdeckt (jetzt gelöscht) Antwort, auch der Fehler tritt auf, wenn ein Anruf auf eine leere Funktion gemacht wird emplace
vor dem Aufruf:
template <typename TVec>
void a(TVec&) { }
int main()
{
std::vector<std::pair<int, Val>> v;
a(v);
v.emplace(std::begin(v), 0, Val{});
}
a(v);
Commeting aus oben verhindert, dass der Kompilierungsfehler erzeugt wird. Dieses Verhalten ist sowohl in g ++ 7 als auch in clang ++ 5 vorhanden.
Eine andere seltsame Fall von Sergey Murzin entdeckt wurde, und kann on wandbox getestet werden:
int main()
{
std::vector<std::pair<int, Val>> v;
v.emplace(v.begin(), 0, Val{});
std::cout << v.back().first << std::endl;
}
Der obige Code erzeugt einen Compiler-Fehler. Das Auskommentieren der Zeile, die std::cout
enthält, verhindert, dass der Fehler auftritt. Dieses Verhalten ist sowohl in g ++ 7 als auch in clang ++ 5 vorhanden.
[dcl.spec.auto]/11 "Wenn der Typ einer Entität mit einem nichtdeducated Platzhaltertyp benötigt wird, um den Typ eines zu bestimmen Ausdruck, das Programm ist schlecht geformt. " Also ich denke, dein erstes Programm ist schlecht geformt. (Der Standard sagt nicht "keine Diagnose erforderlich", so dass es eine Diagnose geben sollte). –
Ziemlich sicher, dass dies unter der Anforderung fällt, dass der Compiler nur Funktionen berücksichtigt, die vor der Vorlage definiert wurden, die es zu instanziieren versucht. Könnte immer noch ein Fehler sein, da ich mir bei den Regeln nicht 100% ig sicher bin. – NathanOliver
Ich denke, wir könnten darüber streiten, ob die Verwendung von _T2 in 'pair :: operator = 'Instanziierung als" den Typ eines Ausdrucks bestimmen " –