Biorąc pod uwagę ten program:`pair :: operator = (pair &&)` błąd z `auto &` wyprowadzonymi operacjami przenoszenia - regresja libstdC++?
struct Val
{
Val() = default;
Val(Val&&) = default;
auto& operator=(Val&&);
};
/* PLACEHOLDER */
auto& Val::operator=(Val&&) { return *this; }
zastępując /* PLACEHOLDER */
z ...
int main()
{
std::vector<std::pair<int, Val>> v;
v.emplace(std::begin(v), 0, Val{});
}
... kompiluje pomyślnie:
- g ++ 6.2.0
- g ++ 6.3.0
g ++ 7.0.1 (trunk)
dzyń ++ 3.9.1
- dzyń ++ 5.0.0 (HEAD)
Podstawiając /* PLACEHOLDER */
z ...
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);
}
... kompiluje pomyślnie:
- g ++ 6.2.0
- Clang ++ 3.9.1
... ale powoduje błąd kompilacji na:
- g ++ 6.3.0
- g ++ 7.0.1 (pień)
- dzyń ++ 5.0.0 (HEAD)
Wytworzona błąd wydaje się być związane z nieswobodnego pair operator=(pair&&)
przeciążeniem - 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;
}
Podstawienie
is_move_assignable<_T2>
za pomocąstd::true_type
pozwala na kod do kompilacji.Przeniesienie definicji
Val::operator=(Val&&)
przed/* PLACEHOLDER */
umożliwia kod do kompilacji.Zmiana
auto& Val::operator=(Val&&)
naVal& Val::operator=(Val&&)
umożliwia kod do kompilacji.
Co się tutaj dzieje? Czy jest to defekt implementacji w najnowszej wersji libstdC++? A może starsze wersje nieprawidłowo kompilowały źle sformułowany kod?
EDIT: jak AndyG odkryto w jego (obecnie skreślony) odpowiedź, błąd występuje również, gdy wezwanie do pustej funkcji jest wykonany przed wywołaniem emplace
:
template <typename TVec>
void a(TVec&) { }
int main()
{
std::vector<std::pair<int, Val>> v;
a(v);
v.emplace(std::begin(v), 0, Val{});
}
Commeting się a(v);
powyżej zapobiega powstawaniu błędu podczas kompilacji. To zachowanie występuje zarówno w g ++ 7, jak i clang ++ 5.
Kolejna dziwna sprawa została odkryta przez Sergey Murzin i mogą być testowane na on wandbox:
int main()
{
std::vector<std::pair<int, Val>> v;
v.emplace(v.begin(), 0, Val{});
std::cout << v.back().first << std::endl;
}
Powyższy kod powoduje błąd kompilatora. Komentowanie linii zawierającej std::cout
zapobiega wystąpieniu błędu. To zachowanie występuje zarówno w g ++ 7, jak i clang ++ 5.
[dcl.spec.auto]/11 "Jeśli typ obiektu z nieuprawnionym typem zastępczym jest potrzebny do określenia typu wypowiedzi, program jest źle sformułowany. " Więc myślę, że twój pierwszy program jest źle sformułowany. (Standard nie mówi "nie wymaga diagnostyki", więc powinna istnieć diagnoza). –
Dość pewna jest to, że kompilator bierze pod uwagę tylko funkcje zdefiniowane przed szablonem, który próbuje utworzyć. Nadal może być błędem, ponieważ nie jestem w 100% pewien reguł. – NathanOliver
Myślę, że moglibyśmy spierać się o to, czy użycie _T2 w instancji 'pair :: operator =' liczy się jako "określenie typu wyrażenia" –