Use defined for some preprocessor variables that might be undefined (#2476)

The variables PYBIND11_HAS_OPTIONAL, PYBIND11_HAS_EXP_OPTIONAL, PYBIND11_HAS_VARIANT,
__clang__, __APPLE__ were not checked for defined in a minortity of instances.

If the project using pybind11 sets -Wundef, the warnings will show.

The test build is also modified to catch the problem.
diff --git a/include/pybind11/stl.h b/include/pybind11/stl.h
index 6c2bebd..721bb66 100644
--- a/include/pybind11/stl.h
+++ b/include/pybind11/stl.h
@@ -289,7 +289,7 @@
     PYBIND11_TYPE_CASTER(T, _("Optional[") + value_conv::name + _("]"));
 };
 
-#if PYBIND11_HAS_OPTIONAL
+#if defined(PYBIND11_HAS_OPTIONAL)
 template<typename T> struct type_caster<std::optional<T>>
     : public optional_caster<std::optional<T>> {};
 
@@ -297,7 +297,7 @@
     : public void_caster<std::nullopt_t> {};
 #endif
 
-#if PYBIND11_HAS_EXP_OPTIONAL
+#if defined(PYBIND11_HAS_EXP_OPTIONAL)
 template<typename T> struct type_caster<std::experimental::optional<T>>
     : public optional_caster<std::experimental::optional<T>> {};
 
@@ -369,7 +369,7 @@
     PYBIND11_TYPE_CASTER(Type, _("Union[") + detail::concat(make_caster<Ts>::name...) + _("]"));
 };
 
-#if PYBIND11_HAS_VARIANT
+#if defined(PYBIND11_HAS_VARIANT)
 template <typename... Ts>
 struct type_caster<std::variant<Ts...>> : variant_caster<std::variant<Ts...>> { };
 #endif
diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt
index 54f13fd..e59c75c 100644
--- a/tests/CMakeLists.txt
+++ b/tests/CMakeLists.txt
@@ -216,7 +216,7 @@
     target_compile_options(${target_name} PRIVATE /W4)
   elseif(CMAKE_CXX_COMPILER_ID MATCHES "(GNU|Intel|Clang)" AND NOT PYBIND11_CUDA_TESTS)
     target_compile_options(${target_name} PRIVATE -Wall -Wextra -Wconversion -Wcast-qual
-                                                  -Wdeprecated)
+                                                  -Wdeprecated -Wundef)
   endif()
 
   if(PYBIND11_WERROR)
diff --git a/tests/test_operator_overloading.cpp b/tests/test_operator_overloading.cpp
index f3c2eaa..d176c46 100644
--- a/tests/test_operator_overloading.cpp
+++ b/tests/test_operator_overloading.cpp
@@ -88,11 +88,11 @@
   // Here, we suppress the warning using `#pragma diagnostic`.
   // Taken from: https://github.com/RobotLocomotion/drake/commit/aaf84b46
   // TODO(eric): This could be resolved using a function / functor (e.g. `py::self()`).
-  #if (__APPLE__) && (__clang__)
+  #if defined(__APPLE__) && defined(__clang__)
     #if (__clang_major__ >= 10) && (__clang_minor__ >= 0) && (__clang_patchlevel__ >= 1)
       #pragma GCC diagnostic ignored "-Wself-assign-overloaded"
     #endif
-  #elif (__clang__)
+  #elif defined(__clang__)
     #if (__clang_major__ >= 7)
       #pragma GCC diagnostic ignored "-Wself-assign-overloaded"
     #endif
diff --git a/tests/test_stl.cpp b/tests/test_stl.cpp
index 9286357..b230717 100644
--- a/tests/test_stl.cpp
+++ b/tests/test_stl.cpp
@@ -15,7 +15,7 @@
 #include <string>
 
 // Test with `std::variant` in C++17 mode, or with `boost::variant` in C++11/14
-#if PYBIND11_HAS_VARIANT
+#if defined(PYBIND11_HAS_VARIANT)
 using std::variant;
 #elif defined(PYBIND11_TEST_BOOST) && (!defined(_MSC_VER) || _MSC_VER >= 1910)
 #  include <boost/variant.hpp>