mirror of
https://github.com/fmtlib/fmt.git
synced 2026-10-29 02:17:28 +08:00
Fix C++11 build of padded range/tuple formatting
if constexpr is a C++17 feature and broke the clang-3.6 c++11 job (and -Werror builds on macos). Replace the dispatch with three write_padded overloads selected by FMT_ENABLE_IF, which works in C++11 and keeps the same behavior for appender contexts, generic back-insert iterators, and a hard error otherwise. Signed-off-by: linsen <251731047+linsen458-spec@users.noreply.github.com>
This commit is contained in:
parent
134d974f81
commit
fb12b23a17
@ -4088,36 +4088,60 @@ template <typename Char> class nested_format_specs {
|
||||
auto specs = specs_;
|
||||
handle_dynamic_spec(specs.dynamic_width(), specs.width, width_ref_, ctx);
|
||||
if (specs.width == 0) return f.write_body(ctx, static_cast<T&&>(values)...);
|
||||
return write_padded(ctx, f, specs, static_cast<T&&>(values)...);
|
||||
}
|
||||
|
||||
// The body is formatted into a temporary buffer so that it can be padded.
|
||||
// This requires a context that writes to the buffer while sharing the
|
||||
// args of `ctx`, which is only possible when an output iterator of the
|
||||
// context type can be pointed at storage owned here: an appender
|
||||
// (context) or a back insert iterator (generic_context, used by the
|
||||
// compile-time API and format_to with custom iterators).
|
||||
using iterator = typename FormatContext::iterator;
|
||||
if constexpr (std::is_same<iterator, basic_appender<Char>>::value) {
|
||||
auto buf = basic_memory_buffer<Char>();
|
||||
auto buffer_ctx =
|
||||
FormatContext(basic_appender<Char>(buf), ctx.args(), ctx.locale());
|
||||
f.write_body(buffer_ctx, static_cast<T&&>(values)...);
|
||||
return detail::write<Char>(
|
||||
ctx.out(), basic_string_view<Char>(buf.data(), buf.size()), specs);
|
||||
} else if constexpr (is_back_insert_iterator<iterator>::value) {
|
||||
using container = typename iterator::container_type;
|
||||
container storage;
|
||||
auto buffer_ctx =
|
||||
FormatContext(iterator(storage), ctx.args(), ctx.locale());
|
||||
f.write_body(buffer_ctx, static_cast<T&&>(values)...);
|
||||
auto buf = basic_memory_buffer<Char>();
|
||||
for (auto value : storage) buf.push_back(value);
|
||||
return detail::write<Char>(
|
||||
ctx.out(), basic_string_view<Char>(buf.data(), buf.size()), specs);
|
||||
} else {
|
||||
// Cannot create an output iterator of the context type that writes
|
||||
// into a temporary buffer.
|
||||
FMT_THROW(format_error("cannot pad output with this iterator type"));
|
||||
}
|
||||
private:
|
||||
// The body is formatted into a temporary buffer so that it can be padded.
|
||||
// This requires a context that writes to the buffer while sharing the
|
||||
// args of `ctx`, which is only possible when an output iterator of the
|
||||
// context type can be pointed at storage owned here: an appender
|
||||
// (context) or a back insert iterator (generic_context, used by the
|
||||
// compile-time API and format_to with custom iterators).
|
||||
template <typename FormatContext, typename F, typename... T,
|
||||
FMT_ENABLE_IF(std::is_same<typename FormatContext::iterator,
|
||||
basic_appender<Char>>::value)>
|
||||
FMT_CONSTEXPR auto write_padded(FormatContext& ctx, const F& f,
|
||||
const format_specs& specs,
|
||||
T&&... values) const -> decltype(ctx.out()) {
|
||||
auto buf = basic_memory_buffer<Char>();
|
||||
auto buffer_ctx =
|
||||
FormatContext(basic_appender<Char>(buf), ctx.args(), ctx.locale());
|
||||
f.write_body(buffer_ctx, static_cast<T&&>(values)...);
|
||||
return detail::write<Char>(
|
||||
ctx.out(), basic_string_view<Char>(buf.data(), buf.size()), specs);
|
||||
}
|
||||
|
||||
template <typename FormatContext, typename F, typename... T,
|
||||
FMT_ENABLE_IF(!std::is_same<typename FormatContext::iterator,
|
||||
basic_appender<Char>>::value&&
|
||||
is_back_insert_iterator<
|
||||
typename FormatContext::iterator>::value)>
|
||||
FMT_CONSTEXPR auto write_padded(FormatContext& ctx, const F& f,
|
||||
const format_specs& specs,
|
||||
T&&... values) const -> decltype(ctx.out()) {
|
||||
using container =
|
||||
typename FormatContext::iterator::container_type;
|
||||
container storage;
|
||||
auto buffer_ctx =
|
||||
FormatContext(typename FormatContext::iterator(storage), ctx.args(),
|
||||
ctx.locale());
|
||||
f.write_body(buffer_ctx, static_cast<T&&>(values)...);
|
||||
auto buf = basic_memory_buffer<Char>();
|
||||
for (auto value : storage) buf.push_back(value);
|
||||
return detail::write<Char>(
|
||||
ctx.out(), basic_string_view<Char>(buf.data(), buf.size()), specs);
|
||||
}
|
||||
|
||||
template <typename FormatContext, typename F, typename... T,
|
||||
FMT_ENABLE_IF(
|
||||
!is_back_insert_iterator<typename FormatContext::iterator>::value)>
|
||||
FMT_CONSTEXPR auto write_padded(FormatContext& ctx, const F& f,
|
||||
const format_specs& specs,
|
||||
T&&... values) const -> decltype(ctx.out()) {
|
||||
// Cannot create an output iterator of the context type that writes
|
||||
// into a temporary buffer.
|
||||
FMT_THROW(format_error("cannot pad output with this iterator type"));
|
||||
}
|
||||
};
|
||||
} // namespace detail
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user