https://gcc.gnu.org/bugzilla/show_bug.cgi?id=95606
Jonathan Wakely <redi at gcc dot gnu.org> changed: What |Removed |Added ---------------------------------------------------------------------------- Resolution|--- |INVALID Status|UNCONFIRMED |RESOLVED --- Comment #2 from Jonathan Wakely <redi at gcc dot gnu.org> --- I think this is not a bug in GCC. A specialization of std::swap still depends on the signature of the primary template, and that primary template requires the argument types to be swappable. The is_swappable trait requires move_constructible, and that requires complete types. Checking is_move_constructible<json> will perform overload resolution which considers the basic_json(json_ref) constructor, which tries to see if json_ref can be constructed from a basic_json rvalue, which checks the constraint on the json_ref constructor, which depends on basic_json, which is incomplete at this point. The json code is incorrect and should be fixed. The std::swap<json> specialization is wrong and should be replaced by a normal (non-template) overload in the same namespace as the json type: void swap(json&, json&) noexcept; The json_ref constructor should be constrained to avoid recursive instantiations with incomplete types, e.g. template<typename T, typename U> using is_not = std::is_same<std::remove_cv_t<std::remove_reference_t<T>>, U>; class json_ref { public: template <typename T, typename = std::enable_if_t<!is_not<T, json_ref>::value>, typename = std::enable_if_t<!is_not<T, json>::value>, bool = std::is_constructible<json, T>::value> json_ref(T &&){} };