Mam taki kod:
#include <vector>
#include <utility>
int main()
{
std::vector<bool> vb{true, false};
std::swap(vb[0], vb[1]);
}
vector<bool>
Pomijając argumenty na temat rozsądku , działało to dobrze:
- Clang dla komputerów Mac
- Visual Studio dla Windows
- GCC dla systemu Linux
Następnie próbowałem zbudować go za pomocą Clanga w systemie Windows i otrzymałem następujący błąd (skrócony):
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>&&
Dziwi mnie, że wyniki różnią się w zależności od implementacji.
Dlaczego nie działa z Clangiem w systemie Windows?
operator[]
? i możestd::swap
działać na wartościach i wartościach?/permissive-
(zgodnością), co i tak powinno być ogólnie używane;)Odpowiedzi:
Standard nie wymaga tego do kompilacji na żadnym zestawie narzędzi!
Po pierwsze,
vector<bool>
to dziwne, a indeksowanie daje tymczasowy obiekt typu proxystd::vector<bool>::reference
, a nie rzeczywistybool&
.Komunikat o błędzie mówi ci, że nie może powiązać tego tymczasowego z
const
odwołaniem innym niż wartość w ogólnejtemplate <typename T> std::swap(T& lhs, T& rhs)
implementacji.Rozszerzenia!
Jednak okazuje się, że libstdc ++ definiuje przeciążenie dla
std::swap(std::vector<bool>::reference, std::vector<bool>::reference)
, ale ten jest rozszerzeniem standardu (lub, jeśli jest tam, nie mogę znaleźć żadnych dowodów na to).Libc ++ też to robi .
Domyślam się, że implementacja stdlib programu Visual Studio, której nadal używasz, nie robi tego , ale aby dodać obrażenia do obrażeń , możesz powiązać tymczasowe odniesienia do wartości z VS (chyba że używasz trybu zgodności), więc standardowa, „ogólna”
std::swap
funkcja działa do momentu zastąpienia kompilatora VS bardziej restrykcyjnym kompilatorem Clanga.W rezultacie polegałeś na rozszerzeniach we wszystkich trzech łańcuchach narzędzi, dla których działał on dla Ciebie, a kombinacja Clang na Windows jest jedyną faktycznie wykazującą ścisłą zgodność.
(Moim zdaniem te trzy łańcuchy narzędzi powinny to zdiagnozować, więc cały czas nie wysyłałeś nieprzenośnego kodu.)
Co teraz?
Dodanie własnej specjalizacji
std::swap
i może być kuszącestd::vector<bool>::reference
, ale nie można tego robić w przypadku standardowych typów; w rzeczywistości byłoby to sprzeczne z przeciążeniami, które libstdc ++ i libc ++ zdecydowały się dodać jako rozszerzenia.Aby być przenośnym i zgodnym, należy zmienić kod .
Być może dobry, staromodny:
Lub skorzystaj ze specjalnej statycznej funkcji składowej, która robi dokładnie to, co chciałeś :
Również pisownia w następujący sposób:
źródło
std::vector<bool>::reference
nic nie jest źle sformułowane. Wydaje mi się, że użycie czegoś takiegochar * foo = "bar";
wymagałoby diagnostyki, ponieważ jest to źle sformułowane.