@@ -860,6 +860,27 @@ struct is_recursive_container : any_of<is_container_with_recursive_value_type<Co
860860template <typename T, typename SFINAE = void >
861861struct is_move_constructible : std::is_move_constructible<T> {};
862862
863+ // Specialization for types that appear to be move constructible but also look like stl containers
864+ // (we specifically check for: has `value_type` and `reference` with `reference = value_type&`): if
865+ // so, move constructability depends on whether the value_type is move constructible.
866+ template <typename Container>
867+ struct is_move_constructible <
868+ Container,
869+ enable_if_t <
870+ all_of<std::is_move_constructible<Container>,
871+ std::is_same<typename Container::value_type &, typename Container::reference>,
872+ // Avoid infinite recursion
873+ negation<is_recursive_container<Container>>>::value>>
874+ : is_move_constructible<typename Container::value_type> {};
875+
876+ // Likewise for std::pair
877+ // (after C++17 it is mandatory that the move constructor not exist when the two types aren't
878+ // themselves move constructible, but this can not be relied upon when T1 or T2 are themselves
879+ // containers).
880+ template <typename T1, typename T2>
881+ struct is_move_constructible <std::pair<T1, T2>>
882+ : all_of<is_move_constructible<T1>, is_move_constructible<T2>> {};
883+
863884// std::is_copy_constructible isn't quite enough: it lets std::vector<T> (and similar) through when
864885// T is non-copyable, but code containing such a copy constructor fails to actually compile.
865886template <typename T, typename SFINAE = void >
0 commit comments