diff --git a/cpp/apidoc/Doxyfile b/cpp/apidoc/Doxyfile
index e19c933cd454..5be93032c00d 100644
--- a/cpp/apidoc/Doxyfile
+++ b/cpp/apidoc/Doxyfile
@@ -2168,16 +2168,17 @@ INCLUDE_FILE_PATTERNS  =
 
 PREDEFINED             = __attribute__(x)= \
                          __declspec(x)= \
-                         PARQUET_EXPORT= \
-                         GANDIVA_EXPORT= \
-                         ARROW_EXPORT= \
                          ARROW_ACERO_EXPORT= \
+                         ARROW_ARG_UNUSED(x)=x \
+                         ARROW_DEPRECATED(x)= \
                          ARROW_DS_EXPORT= \
                          ARROW_ENGINE_EXPORT= \
+                         ARROW_EXPORT= \
+                         ARROW_EXTERN_TEMPLATE= \
                          ARROW_FLIGHT_EXPORT= \
                          ARROW_FLIGHT_SQL_EXPORT= \
-                         ARROW_EXTERN_TEMPLATE= \
-                         ARROW_DEPRECATED(x)=
+                         GANDIVA_EXPORT= \
+                         PARQUET_EXPORT=
 
 # If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then this
 # tag can be used to specify a list of macro names that should be expanded. The
diff --git a/cpp/cmake_modules/SetupCxxFlags.cmake b/cpp/cmake_modules/SetupCxxFlags.cmake
index d56609c12396..ea357b47794c 100644
--- a/cpp/cmake_modules/SetupCxxFlags.cmake
+++ b/cpp/cmake_modules/SetupCxxFlags.cmake
@@ -314,6 +314,7 @@ if("${BUILD_WARNING_LEVEL}" STREQUAL "CHECKIN")
     set(CXX_COMMON_FLAGS "${CXX_COMMON_FLAGS} -Wall")
     set(CXX_COMMON_FLAGS "${CXX_COMMON_FLAGS} -Wextra")
     set(CXX_COMMON_FLAGS "${CXX_COMMON_FLAGS} -Wdocumentation")
+    set(CXX_COMMON_FLAGS "${CXX_COMMON_FLAGS} -DARROW_WARN_DOCUMENTATION")
     if(CMAKE_SYSTEM_NAME STREQUAL "Emscripten")
       # size_t is 32 bit in Emscripten wasm32 - ignore conversion errors
       set(CXX_COMMON_FLAGS "${CXX_COMMON_FLAGS} -Wno-shorten-64-to-32")
diff --git a/cpp/src/arrow/array/builder_base.h b/cpp/src/arrow/array/builder_base.h
index e6c0b2d2387f..3a85318735f8 100644
--- a/cpp/src/arrow/array/builder_base.h
+++ b/cpp/src/arrow/array/builder_base.h
@@ -175,9 +175,9 @@ class ARROW_EXPORT ArrayBuilder {
   /// \brief Append a range of values from an array.
   ///
   /// The given array must be the same type as the builder.
-  virtual Status AppendArraySlice([[maybe_unused]] const ArraySpan& array,
-                                  [[maybe_unused]] int64_t offset,
-                                  [[maybe_unused]] int64_t length) {
+  virtual Status AppendArraySlice(const ArraySpan& ARROW_ARG_UNUSED(array),
+                                  int64_t ARROW_ARG_UNUSED(offset),
+                                  int64_t ARROW_ARG_UNUSED(length)) {
     return Status::NotImplemented("AppendArraySlice for builder for ", *type());
   }
 
diff --git a/cpp/src/arrow/array/builder_nested.h b/cpp/src/arrow/array/builder_nested.h
index 9f7b0fcdbce0..6089cf04d421 100644
--- a/cpp/src/arrow/array/builder_nested.h
+++ b/cpp/src/arrow/array/builder_nested.h
@@ -248,7 +248,7 @@ class ARROW_EXPORT VarLengthListLikeBuilder : public ArrayBuilder {
   /// \brief Append dimensions for a single list slot.
   ///
   /// ListViewBuilder overrides this to also append the size.
-  virtual void UnsafeAppendDimensions(int64_t offset, [[maybe_unused]] int64_t size) {
+  virtual void UnsafeAppendDimensions(int64_t offset, int64_t ARROW_ARG_UNUSED(size)) {
     offsets_builder_.UnsafeAppend(static_cast<offset_type>(offset));
   }
 
diff --git a/cpp/src/arrow/array/builder_primitive.h b/cpp/src/arrow/array/builder_primitive.h
index db8d2cbaabb6..de7af1b46bde 100644
--- a/cpp/src/arrow/array/builder_primitive.h
+++ b/cpp/src/arrow/array/builder_primitive.h
@@ -32,10 +32,10 @@ namespace arrow {
 class ARROW_EXPORT NullBuilder : public ArrayBuilder {
  public:
   explicit NullBuilder(MemoryPool* pool = default_memory_pool(),
-                       [[maybe_unused]] int64_t alignment = kDefaultBufferAlignment)
+                       int64_t ARROW_ARG_UNUSED(alignment) = kDefaultBufferAlignment)
       : ArrayBuilder(pool) {}
 
-  explicit NullBuilder([[maybe_unused]] const std::shared_ptr<DataType>& type,
+  explicit NullBuilder(const std::shared_ptr<DataType>& ARROW_ARG_UNUSED(type),
                        MemoryPool* pool = default_memory_pool(),
                        int64_t alignment = kDefaultBufferAlignment)
       : NullBuilder(pool, alignment) {}
diff --git a/cpp/src/arrow/device.h b/cpp/src/arrow/device.h
index 3003bad7c459..a591167ef9a4 100644
--- a/cpp/src/arrow/device.h
+++ b/cpp/src/arrow/device.h
@@ -140,7 +140,7 @@ class ARROW_EXPORT Device : public std::enable_shared_from_this<Device>,
   /// derived from Device::Stream to allow for stream ordered events
   /// and memory allocations.
   virtual Result<std::shared_ptr<Stream>> MakeStream(
-      [[maybe_unused]] unsigned int flags) {
+      unsigned int ARROW_ARG_UNUSED(flags)) {
     return NULLPTR;
   }
 
@@ -151,8 +151,8 @@ class ARROW_EXPORT Device : public std::enable_shared_from_this<Device>,
   ///        a no-op function can be passed to indicate ownership is maintained
   ///        externally
   virtual Result<std::shared_ptr<Stream>> WrapStream(
-      [[maybe_unused]] void* device_stream,
-      [[maybe_unused]] Stream::release_fn_t release_fn) {
+      void* ARROW_ARG_UNUSED(device_stream),
+      Stream::release_fn_t ARROW_ARG_UNUSED(release_fn)) {
     return NULLPTR;
   }
 
diff --git a/cpp/src/arrow/type.h b/cpp/src/arrow/type.h
index 58c9df04ec5c..bb05e6efdb98 100644
--- a/cpp/src/arrow/type.h
+++ b/cpp/src/arrow/type.h
@@ -1723,7 +1723,7 @@ class ARROW_EXPORT MonthIntervalType : public IntervalType {
 
   MonthIntervalType() : IntervalType(type_id) {}
 
-  std::string ToString([[maybe_unused]] bool show_metadata = false) const override {
+  std::string ToString(bool ARROW_ARG_UNUSED(show_metadata) = false) const override {
     return name();
   }
   std::string name() const override { return "month_interval"; }
@@ -1761,7 +1761,7 @@ class ARROW_EXPORT DayTimeIntervalType : public IntervalType {
 
   int bit_width() const override { return static_cast<int>(sizeof(c_type) * CHAR_BIT); }
 
-  std::string ToString([[maybe_unused]] bool show_metadata = false) const override {
+  std::string ToString(bool ARROW_ARG_UNUSED(show_metadata) = false) const override {
     return name();
   }
   std::string name() const override { return "day_time_interval"; }
@@ -1803,7 +1803,7 @@ class ARROW_EXPORT MonthDayNanoIntervalType : public IntervalType {
 
   int bit_width() const override { return static_cast<int>(sizeof(c_type) * CHAR_BIT); }
 
-  std::string ToString([[maybe_unused]] bool show_metadata = false) const override {
+  std::string ToString(bool ARROW_ARG_UNUSED(show_metadata) = false) const override {
     return name();
   }
   std::string name() const override { return "month_day_nano_interval"; }
diff --git a/cpp/src/arrow/util/macros.h b/cpp/src/arrow/util/macros.h
index d80828869b33..d0c05a790825 100644
--- a/cpp/src/arrow/util/macros.h
+++ b/cpp/src/arrow/util/macros.h
@@ -67,7 +67,11 @@
 // [5] J. Doerfert et al. 2019. "Performance Exploration Through Optimistic Static
 //     Program Annotations". https://github.com/jdoerfert/PETOSPA/blob/master/ISC19.pdf
 #define ARROW_UNUSED(x) (void)(x)
+#ifdef ARROW_WARN_DOCUMENTATION
+#define ARROW_ARG_UNUSED(x) x
+#else
 #define ARROW_ARG_UNUSED(x)
+#endif
 #if defined(__GNUC__)  // GCC and compatible compilers (clang, Intel ICC)
 #define ARROW_NORETURN __attribute__((noreturn))
 #define ARROW_NOINLINE __attribute__((noinline))
