J'ai un code comme celui-ci:
#include <vector>
#include <utility>
int main()
{
std::vector<bool> vb{true, false};
std::swap(vb[0], vb[1]);
}
Arguments sur la raison de vector<bool>
côté, cela fonctionnait très bien sur:
- Clang pour Mac
- Visual Studio pour Windows
- GCC pour Linux
Ensuite, j'ai essayé de le construire avec Clang sur Windows et j'ai reçu l'erreur suivante (abrégée):
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>&&
Je suis surpris que les résultats diffèrent selon les implémentations.
Pourquoi cela ne fonctionne-t-il pas avec Clang sous Windows?
operator[]
une valeur l? et peutstd::swap
fonctionner sur rvalues et xvalues?/permissive-
(conformité), qui devrait généralement être utilisé de toute façon;)Réponses:
La norme n'exige pas cela pour compiler sur n'importe quelle chaîne d' outils!
Rappelez-vous d'abord que
vector<bool>
c'est bizarre et que l'indexation vous donne un objet temporaire d'un type proxy appeléstd::vector<bool>::reference
, plutôt qu'un réelbool&
.Le message d'erreur vous indique qu'il ne peut pas lier ce temporaire à une
const
référence non lvalue dans l'template <typename T> std::swap(T& lhs, T& rhs)
implémentation générique .Extensions!
Cependant, il s'avère que libstdc ++ définit une surcharge pour
std::swap(std::vector<bool>::reference, std::vector<bool>::reference)
, mais c'est une extension de la norme (ou, si elle est là-dedans, je ne trouve aucune preuve pour cela).libc ++ fait aussi cela .
Je suppose que l'implémentation stdlib de Visual Studio, que vous utilisez toujours, ne fonctionne pas , mais pour ajouter une insulte à une blessure, vous pouvez lier des références temporaires à des références de valeur dans VS (sauf si vous utilisez le mode de conformité), de sorte que le la fonction standard, "générique",
std::swap
fonctionne jusqu'à ce que vous remplaciez le compilateur VS par le compilateur Clang plus strict.En conséquence, vous vous êtes appuyé sur des extensions sur les trois chaînes d'outils pour lesquelles cela a fonctionné pour vous, et la combinaison Clang sur Windows est la seule à afficher une stricte conformité.
(À mon avis, ces trois chaînes d'outils auraient dû diagnostiquer cela afin que vous n'ayez pas expédié de code non portable pendant tout ce temps. 😊)
Et maintenant?
Il peut être tentant d'ajouter votre propre spécialisation de
std::swap
etstd::vector<bool>::reference
, mais vous n'êtes pas autorisé à le faire pour les types standard; en effet, cela entrerait en conflit avec les surcharges que libstdc ++ et libc ++ ont choisi d'ajouter en tant qu'extensions.Donc, pour être portable et conforme, vous devez changer votre code .
Peut-être un bon vieux jeu:
Ou utilisez la fonction membre statique spéciale qui fait exactement ce que vous vouliez :
Également épelable comme suit:
la source
std::vector<bool>::reference
donc rien n'est mal formé. Pour moi, cela ressemble à l'utilisation de quelque chosechar * foo = "bar";
qui nécessiterait un diagnostic car il est mal formé.