diff --git a/include/fmt/format.h b/include/fmt/format.h index 44c2a3b4..7fc94652 100644 --- a/include/fmt/format.h +++ b/include/fmt/format.h @@ -465,25 +465,50 @@ class counting_iterator { value_type operator*() const { return {}; } }; -template class truncating_iterator_base { +// Used to ensure that truncating_iterator SFINAEs properly on the underlying +// iterator's default constructibility. +template ::type> +class truncating_iterator_default_construct_base; + +template +class truncating_iterator_default_construct_base { protected: OutputIt out_; - size_t limit_; - size_t count_; + truncating_iterator_default_construct_base() = delete; +}; + +template +class truncating_iterator_default_construct_base { + protected: + OutputIt out_; + + truncating_iterator_default_construct_base() = default; +}; + +template class truncating_iterator_base + : protected truncating_iterator_default_construct_base { + protected: + size_t limit_ = 0; + size_t count_ = 0; + + truncating_iterator_base() = default; + truncating_iterator_base(OutputIt out, size_t limit) - : out_(out), limit_(limit), count_(0) {} + : truncating_iterator_default_construct_base(out), + limit_(limit), count_(0) {} public: using iterator_category = std::output_iterator_tag; using value_type = typename std::iterator_traits::value_type; - using difference_type = void; + using difference_type = std::ptrdiff_t; using pointer = void; using reference = void; using _Unchecked_type = truncating_iterator_base; // Mark iterator as checked. - OutputIt base() const { return out_; } + OutputIt base() const { return this->out_; } size_t count() const { return count_; } }; @@ -502,6 +527,8 @@ class truncating_iterator public: using value_type = typename truncating_iterator_base::value_type; + truncating_iterator() = default; + truncating_iterator(OutputIt out, size_t limit) : truncating_iterator_base(out, limit) {} @@ -525,6 +552,8 @@ template class truncating_iterator : public truncating_iterator_base { public: + truncating_iterator() = default; + truncating_iterator(OutputIt out, size_t limit) : truncating_iterator_base(out, limit) {} diff --git a/test/format-test.cc b/test/format-test.cc index 34b4ca48..00982f38 100644 --- a/test/format-test.cc +++ b/test/format-test.cc @@ -15,6 +15,7 @@ #include #include #include +#include // Check if fmt/format.h compiles with windows.h included before it. #ifdef _WIN32 @@ -157,6 +158,16 @@ TEST(IteratorTest, TruncatingIterator) { EXPECT_EQ(it.base(), p + 1); } + +TEST(IteratorTest, TruncatingIteratorDefaultConstruct) { + static_assert( + std::is_default_constructible_v>); + + fmt::detail::truncating_iterator it; + EXPECT_EQ(it.base(), nullptr); + EXPECT_EQ(it.count(), 0); +} + TEST(IteratorTest, TruncatingBackInserter) { std::string buffer; auto bi = std::back_inserter(buffer);