diff --git a/include/fmt/base.h b/include/fmt/base.h index b40b3bfba237..91345abe82e2 100644 --- a/include/fmt/base.h +++ b/include/fmt/base.h @@ -494,7 +494,8 @@ struct is_back_insert_iterator< // Extracts a reference to the container from *insert_iterator. template -inline auto get_container(OutputIt it) -> typename OutputIt::container_type& { +inline FMT_CONSTEXPR20 auto get_container(OutputIt it) -> + typename OutputIt::container_type& { struct accessor : OutputIt { accessor(OutputIt base) : OutputIt(base) {} using OutputIt::container; @@ -901,7 +902,7 @@ template class buffer { FMT_CONSTEXPR auto data() const noexcept -> const T* { return ptr_; } /// Clears this buffer. - void clear() { size_ = 0; } + FMT_CONSTEXPR void clear() { size_ = 0; } // Tries resizing the buffer to contain `count` elements. If T is a POD type // the new elements may not be initialized. @@ -924,7 +925,15 @@ template class buffer { } /// Appends data to the end of the buffer. - template void append(const U* begin, const U* end) { + template +// Workaround for Visual Studio 2019 to fix error C2893: Failed to specialize +// function template 'void fmt::v11::detail::buffer::append(const U *,const +// U *)' +#ifndef FMT_DETAIL_EXPLICIT_INSTANTIATIONS + FMT_CONSTEXPR20 +#endif + void + append(const U* begin, const U* end) { while (begin != end) { auto count = to_unsigned(end - begin); try_reserve(size_ + count); @@ -1105,7 +1114,9 @@ template class counting_buffer : public buffer { public: FMT_CONSTEXPR counting_buffer() : buffer(grow, data_, 0, buffer_size) {} - auto count() -> size_t { return count_ + this->size(); } + constexpr auto count() const noexcept -> size_t { + return count_ + this->size(); + } }; } // namespace detail @@ -1155,7 +1166,8 @@ template class basic_appender { private: detail::buffer* buffer_; - friend auto get_container(basic_appender app) -> detail::buffer& { + friend FMT_CONSTEXPR20 auto get_container(basic_appender app) + -> detail::buffer& { return *app.buffer_; } @@ -1170,13 +1182,13 @@ template class basic_appender { FMT_CONSTEXPR basic_appender(detail::buffer& buf) : buffer_(&buf) {} - auto operator=(T c) -> basic_appender& { + FMT_CONSTEXPR20 auto operator=(T c) -> basic_appender& { buffer_->push_back(c); return *this; } - auto operator*() -> basic_appender& { return *this; } - auto operator++() -> basic_appender& { return *this; } - auto operator++(int) -> basic_appender { return *this; } + FMT_CONSTEXPR20 auto operator*() -> basic_appender& { return *this; } + FMT_CONSTEXPR20 auto operator++() -> basic_appender& { return *this; } + FMT_CONSTEXPR20 auto operator++(int) -> basic_appender { return *this; } }; using appender = basic_appender; @@ -1188,7 +1200,8 @@ struct is_back_insert_iterator> : std::true_type {}; // An optimized version of std::copy with the output value type (T). template ::value)> -auto copy(InputIt begin, InputIt end, OutputIt out) -> OutputIt { +FMT_CONSTEXPR20 auto copy(InputIt begin, InputIt end, OutputIt out) + -> OutputIt { get_container(out).append(begin, end); return out; } diff --git a/include/fmt/compile.h b/include/fmt/compile.h index 8a632f635ce8..49d077e0c891 100644 --- a/include/fmt/compile.h +++ b/include/fmt/compile.h @@ -488,7 +488,8 @@ auto format_to_n(OutputIt out, size_t n, const S& fmt, Args&&... args) template ::value)> -auto formatted_size(const S& fmt, const Args&... args) -> size_t { +FMT_CONSTEXPR20 auto formatted_size(const S& fmt, const Args&... args) + -> size_t { auto buf = detail::counting_buffer<>(); fmt::format_to(appender(buf), fmt, args...); return buf.count(); diff --git a/include/fmt/format.h b/include/fmt/format.h index 33ed7034f948..76e3b880ad9b 100644 --- a/include/fmt/format.h +++ b/include/fmt/format.h @@ -523,7 +523,7 @@ template = 307 && !FMT_ICC_VERSION __attribute__((no_sanitize("undefined"))) #endif -inline auto +FMT_CONSTEXPR20 inline auto reserve(OutputIt it, size_t n) -> typename OutputIt::value_type* { auto& c = get_container(it); size_t size = c.size(); @@ -532,7 +532,8 @@ reserve(OutputIt it, size_t n) -> typename OutputIt::value_type* { } template -inline auto reserve(basic_appender it, size_t n) -> basic_appender { +FMT_CONSTEXPR20 inline auto reserve(basic_appender it, size_t n) + -> basic_appender { buffer& buf = get_container(it); buf.try_reserve(buf.size() + n); return it; @@ -551,7 +552,8 @@ template constexpr auto to_pointer(OutputIt, size_t) -> T* { return nullptr; } -template auto to_pointer(basic_appender it, size_t n) -> T* { +template +FMT_CONSTEXPR20 auto to_pointer(basic_appender it, size_t n) -> T* { buffer& buf = get_container(it); auto size = buf.size(); buf.try_reserve(size + n); @@ -929,7 +931,7 @@ class basic_memory_buffer : public detail::buffer { using detail::buffer::append; template - void append(const ContiguousRange& range) { + FMT_CONSTEXPR20 void append(const ContiguousRange& range) { append(range.data(), range.data() + range.size()); } }; diff --git a/src/format.cc b/src/format.cc index 391d3a248c26..51d70cd8ad85 100644 --- a/src/format.cc +++ b/src/format.cc @@ -5,6 +5,7 @@ // // For the license information refer to format.h. +#define FMT_DETAIL_EXPLICIT_INSTANTIATIONS 1 #include "fmt/format-inl.h" FMT_BEGIN_NAMESPACE diff --git a/test/compile-test.cc b/test/compile-test.cc index e44eee9f00bd..dcdd0af684a2 100644 --- a/test/compile-test.cc +++ b/test/compile-test.cc @@ -198,7 +198,7 @@ TEST(compile_test, format_to_n) { EXPECT_STREQ("2a", buffer); } -# if 0 +# if FMT_USE_CONSTEVAL TEST(compile_test, constexpr_formatted_size) { FMT_CONSTEXPR20 size_t size = fmt::formatted_size(FMT_COMPILE("{}"), 42); EXPECT_EQ(size, 2);