Tighten CTAD rules: `SharedPtr(nullptr)` and `IntrusiveSharedPtr(nullptr)`
without an explicit template parameter are invalid rather than being shared
pointers pointing to `std::nullptr_t`.

PiperOrigin-RevId: 919575654
diff --git a/riegeli/base/intrusive_shared_ptr.h b/riegeli/base/intrusive_shared_ptr.h
index 32d1a52..17b2fae 100644
--- a/riegeli/base/intrusive_shared_ptr.h
+++ b/riegeli/base/intrusive_shared_ptr.h
@@ -368,7 +368,11 @@
 template <typename T>
 explicit IntrusiveSharedPtr(T* absl_nullable ptr, ShareOwnership)
     -> IntrusiveSharedPtr<T>;
-template <typename T, std::enable_if_t<!std::is_pointer_v<T>, int> = 0>
+template <typename T,
+          std::enable_if_t<
+              std::conjunction_v<std::negation<std::is_same<T, std::nullptr_t>>,
+                                 std::negation<std::is_pointer<T>>>,
+              int> = 0>
 explicit IntrusiveSharedPtr(T&& value) -> IntrusiveSharedPtr<TargetT<T>>;
 
 }  // namespace riegeli
diff --git a/riegeli/base/shared_ptr.h b/riegeli/base/shared_ptr.h
index 84afa01..573eadd 100644
--- a/riegeli/base/shared_ptr.h
+++ b/riegeli/base/shared_ptr.h
@@ -432,7 +432,8 @@
   absl_nullable std::unique_ptr<T, Unrefer> ptr_;
 };
 
-template <typename T>
+template <typename T,
+          std::enable_if_t<!std::is_same_v<T, std::nullptr_t>, int> = 0>
 explicit SharedPtr(T&& value) -> SharedPtr<TargetT<T>>;
 
 }  // namespace riegeli