Ich habe folgenden Code:
#include <vector>
#include <utility>
int main()
{
std::vector<bool> vb{true, false};
std::swap(vb[0], vb[1]);
}
Argumente über die Vernunft vector<bool>
beiseite, das funktionierte gut bei:
- Clang für Mac
- Visual Studio für Windows
- GCC für Linux
Dann habe ich versucht, es mit Clang unter Windows zu erstellen und habe den folgenden Fehler (gekürzt) erhalten:
error: no matching function for call to 'swap'
std::swap(vb[0], vb[1]);
^~~~~~~~~
note: candidate function [with _Ty = std::_Vb_reference<std::_Wrap_alloc<std::allocator<unsigned int> > >, $1 = void] not viable: expects an l-value for 1st argument
inline void swap(_Ty& _Left, _Ty& _Right) _NOEXCEPT_COND(is_nothrow_move_constructible_v<_Ty>&&
Ich bin überrascht, dass die Ergebnisse je nach Implementierung unterschiedlich sind.
Warum funktioniert es nicht mit Clang unter Windows?
operator[]
eines Wertes? und kannstd::swap
mit rWerten und xWerten arbeiten?/permissive-
Antworten:
Der Standard verlangt dies nicht, um in irgendeiner Toolchain zu kompilieren !
Wenn Sie sich zunächst daran erinnern, dass dies
vector<bool>
seltsam ist und wenn Sie es abonnieren, erhalten Sie ein temporäres Objekt eines Proxy-Typs namensstd::vector<bool>::reference
und kein tatsächlichesbool&
.Die Fehlermeldung weist darauf hin, dass diese temporäre
const
Datei nicht an eine nicht wertvolle Referenz in der generischentemplate <typename T> std::swap(T& lhs, T& rhs)
Implementierung gebunden werden kann .Erweiterungen!
Es stellt sich jedoch heraus, dass libstdc ++ eine Überladung für definiert
std::swap(std::vector<bool>::reference, std::vector<bool>::reference)
, dies ist jedoch eine Erweiterung des Standards (oder, falls vorhanden, kann ich keine Beweise dafür finden).libc ++ macht das auch .
Ich würde vermuten, dass die Visual Studio stdlib-Implementierung, die Sie noch verwenden, dies nicht tut , aber um die Verletzung zusätzlich zu beleidigen, können Sie temporäre Werte an l-Wert-Referenzen in VS binden (es sei denn, Sie verwenden den Konformitätsmodus) Die Standardfunktion "generic"
std::swap
funktioniert so lange, bis Sie den VS-Compiler durch den strengeren Clang-Compiler ersetzen.Infolgedessen haben Sie sich bei allen drei Toolchains, für die es für Sie funktioniert hat, auf Erweiterungen verlassen, und die Clang on Windows-Kombination ist die einzige, die tatsächlich strikte Konformität aufweist.
(Meiner Meinung nach hätten diese drei Toolchains dies diagnostizieren sollen, damit Sie nicht die ganze Zeit nicht portierbaren Code ausgeliefert haben. 😊)
Was jetzt?
Es mag verlockend sein, eine eigene Spezialisierung von
std::swap
und hinzuzufügenstd::vector<bool>::reference
, aber Sie dürfen dies nicht für Standardtypen tun. In der Tat würde dies im Widerspruch zu den Überladungen stehen, die libstdc ++ und libc ++ als Erweiterungen hinzugefügt haben.Um portabel und kompatibel zu sein, sollten Sie Ihren Code ändern .
Vielleicht ein guter altmodischer:
Oder nutzen Sie die spezielle statische Elementfunktion, die genau das tut, was Sie wollten :
Auch wie folgt buchstabierbar:
quelle
std::vector<bool>::reference
so dass nichts wirklich schlecht geformt ist. Für mich klingt es so, alschar * foo = "bar";
würde die Verwendung von so etwas wie eine Diagnose erfordern, da diese schlecht geformt ist.