Make truncating_iterator an output_iterator
I agree that my contributions are licensed under the {fmt} license, and agree to future changes to the licensing.

Fixes #2156.
{"label": "fmtlib:master", "ref": "master", "sha": "835b910e7d758efdfdce9f23df1b190deb3373db"}
My formatter for a custom type has C++20 delegates to a function that has a requirement `template <std::output_iterator<char> It>`. Unfortunately, that one fails when used within `fmt::format_to_n`, because the iterator found in `ctx.out()` is of type `fmt::v6::internal::truncating_iterator<char*, std::false_type>`. That one fails to be a `std::output_iterator`, apparently because it is missing default construction. Potentially, there are other requirements missing.

Is there fundamentally preventing that object from being an output iterator, or has the requirement simply not come up before?
truncating_iterator is no std::output_iterator
diff --git a/include/fmt/format.h b/include/fmt/format.h
index 44c2a3b49929..065aa4964bbb 100644
--- a/include/fmt/format.h
+++ b/include/fmt/format.h
@@ -469,15 +469,17 @@ template <typename OutputIt> class truncating_iterator_base {
  protected:
   OutputIt out_;
   size_t limit_;
-  size_t count_;
+  size_t count_ = 0;
 
+  truncating_iterator_base() : out_(), limit_(0) {}
+  
   truncating_iterator_base(OutputIt out, size_t limit)
-      : out_(out), limit_(limit), count_(0) {}
+      : out_(out), limit_(limit) {}
 
  public:
   using iterator_category = std::output_iterator_tag;
   using value_type = typename std::iterator_traits<OutputIt>::value_type;
-  using difference_type = void;
+  using difference_type = std::ptrdiff_t;
   using pointer = void;
   using reference = void;
   using _Unchecked_type =
@@ -502,6 +504,8 @@ class truncating_iterator<OutputIt, std::false_type>
  public:
   using value_type = typename truncating_iterator_base<OutputIt>::value_type;
 
+  truncating_iterator() = default;
+  
   truncating_iterator(OutputIt out, size_t limit)
       : truncating_iterator_base<OutputIt>(out, limit) {}
 
@@ -525,6 +529,8 @@ template <typename OutputIt>
 class truncating_iterator<OutputIt, std::true_type>
     : public truncating_iterator_base<OutputIt> {
  public:
+  truncating_iterator() = default;
+
   truncating_iterator(OutputIt out, size_t limit)
       : truncating_iterator_base<OutputIt>(out, limit) {}
 

diff --git a/test/format-test.cc b/test/format-test.cc
index 34b4ca485aef..a71aeaf1dabc 100644
--- a/test/format-test.cc
+++ b/test/format-test.cc
@@ -12,9 +12,11 @@
 #include <climits>
 #include <cmath>
 #include <cstring>
+#include <iterator>
 #include <list>
 #include <memory>
 #include <string>
+#include <type_traits>
 
 // Check if fmt/format.h compiles with windows.h included before it.
 #ifdef _WIN32
@@ -157,6 +159,24 @@ TEST(IteratorTest, TruncatingIterator) {
   EXPECT_EQ(it.base(), p + 1);
 }
 
+
+TEST(IteratorTest, TruncatingIteratorDefaultConstruct) {
+  static_assert(
+      std::is_default_constructible<fmt::detail::truncating_iterator<char*>>::value,
+      "");
+  
+  fmt::detail::truncating_iterator<char*> it;
+  EXPECT_EQ(nullptr, it.base());
+  EXPECT_EQ(std::size_t{0}, it.count());
+}
+
+#ifdef __cpp_lib_ranges
+TEST(IteratorTest, TruncatingIteratorOutputIterator) {
+  static_assert(std::output_iterator<fmt::detail::truncating_iterator<char*>,
+      char>);
+}
+#endif
+
 TEST(IteratorTest, TruncatingBackInserter) {
   std::string buffer;
   auto bi = std::back_inserter(buffer);

{"locale-test": {"run": "PASS", "test": "NONE", "fix": "PASS"}, "compile-test": {"run": "PASS", "test": "NONE", "fix": "PASS"}, "ostream-test": {"run": "PASS", "test": "NONE", "fix": "PASS"}, "ranges-test": {"run": "PASS", "test": "NONE", "fix": "PASS"}, "core-test": {"run": "PASS", "test": "NONE", "fix": "PASS"}, "scan-test": {"run": "PASS", "test": "NONE", "fix": "PASS"}, "color-test": {"run": "PASS", "test": "NONE", "fix": "PASS"}, "chrono-test": {"run": "PASS", "test": "NONE", "fix": "PASS"}, "format-test": {"run": "PASS", "test": "NONE", "fix": "PASS"}, "gtest-extra-test": {"run": "PASS", "test": "NONE", "fix": "PASS"}, "assert-test": {"run": "PASS", "test": "NONE", "fix": "PASS"}, "posix-mock-test": {"run": "PASS", "test": "NONE", "fix": "PASS"}, "printf-test": {"run": "PASS", "test": "NONE", "fix": "PASS"}, "format-impl-test": {"run": "PASS", "test": "NONE", "fix": "PASS"}, "os-test": {"run": "PASS", "test": "NONE", "fix": "PASS"}, "enforce-compile-string-test": {"run": "PASS", "test": "NONE", "fix": "PASS"}}
{"locale-test": {"run": "PASS", "test": "NONE", "fix": "PASS"}, "compile-test": {"run": "PASS", "test": "NONE", "fix": "PASS"}, "ostream-test": {"run": "PASS", "test": "NONE", "fix": "PASS"}, "ranges-test": {"run": "PASS", "test": "NONE", "fix": "PASS"}, "core-test": {"run": "PASS", "test": "NONE", "fix": "PASS"}, "scan-test": {"run": "PASS", "test": "NONE", "fix": "PASS"}, "color-test": {"run": "PASS", "test": "NONE", "fix": "PASS"}, "chrono-test": {"run": "PASS", "test": "NONE", "fix": "PASS"}, "format-test": {"run": "PASS", "test": "NONE", "fix": "PASS"}, "gtest-extra-test": {"run": "PASS", "test": "NONE", "fix": "PASS"}, "assert-test": {"run": "PASS", "test": "NONE", "fix": "PASS"}, "posix-mock-test": {"run": "PASS", "test": "NONE", "fix": "PASS"}, "printf-test": {"run": "PASS", "test": "NONE", "fix": "PASS"}, "format-impl-test": {"run": "PASS", "test": "NONE", "fix": "PASS"}, "os-test": {"run": "PASS", "test": "NONE", "fix": "PASS"}, "enforce-compile-string-test": {"run": "PASS", "test": "NONE", "fix": "PASS"}}
{"passed_count": 16, "failed_count": 0, "skipped_count": 0, "passed_tests": ["format-test", "gtest-extra-test", "locale-test", "compile-test", "ostream-test", "ranges-test", "assert-test", "posix-mock-test", "core-test", "printf-test", "color-test", "scan-test", "format-impl-test", "os-test", "chrono-test", "enforce-compile-string-test"], "failed_tests": [], "skipped_tests": []}
{"passed_count": 0, "failed_count": 0, "skipped_count": 0, "passed_tests": [], "failed_tests": [], "skipped_tests": []}
{"passed_count": 16, "failed_count": 0, "skipped_count": 0, "passed_tests": ["format-test", "gtest-extra-test", "locale-test", "compile-test", "ostream-test", "ranges-test", "assert-test", "posix-mock-test", "core-test", "printf-test", "color-test", "scan-test", "format-impl-test", "os-test", "chrono-test", "enforce-compile-string-test"], "failed_tests": [], "skipped_tests": []}