Use named argument emulation instead of nested functions
diff --git a/fmt/format.h b/fmt/format.h
index e6ea86d..9a7a99a 100644
--- a/fmt/format.h
+++ b/fmt/format.h
@@ -1639,6 +1639,52 @@
CHAR_FLAG = 0x10 // Argument has char type - used in error reporting.
};
+enum format_spec_tag {fill_tag, align_tag, width_tag, type_tag};
+
+// Format specifier.
+template <typename T, format_spec_tag>
+class format_spec {
+ private:
+ T value_;
+
+ public:
+ typedef T value_type;
+
+ explicit format_spec(T value) : value_(value) {}
+
+ T value() const { return value_; }
+};
+
+template <typename Char>
+using fill_spec = format_spec<Char, fill_tag>;
+
+using width_spec = format_spec<unsigned, width_tag>;
+using type_spec = format_spec<char, type_tag>;
+
+class fill_spec_factory {
+ public:
+ constexpr fill_spec_factory() {}
+
+ template <typename Char>
+ fill_spec<Char> operator=(Char value) const {
+ return fill_spec<Char>(value);
+ }
+};
+
+template <typename FormatSpec>
+class format_spec_factory {
+ public:
+ constexpr format_spec_factory() {}
+
+ FormatSpec operator=(typename FormatSpec::value_type value) const {
+ return FormatSpec(value);
+ }
+};
+
+constexpr fill_spec_factory fill;
+constexpr format_spec_factory<width_spec> width;
+constexpr format_spec_factory<type_spec> type;
+
// An empty format specifier.
struct EmptySpec {};
@@ -1688,15 +1734,40 @@
};
// A full format specifier.
-struct FormatSpec : AlignSpec {
+class FormatSpec : public AlignSpec {
+ private:
+ void set(fill_spec<char> fill) {
+ fill_ = fill.value();
+ }
+
+ void set(width_spec width) {
+ width_ = width.value();
+ }
+
+ void set(type_spec type) {
+ type_ = type.value();
+ }
+
+ template <typename Spec, typename... Specs>
+ void set(Spec spec, Specs... tail) {
+ set(spec);
+ set(tail...);
+ }
+
+ public:
unsigned flags_;
int precision_;
char type_;
- FormatSpec(
- unsigned width = 0, char type = 0, wchar_t fill = ' ')
+ FormatSpec(unsigned width = 0, char type = 0, wchar_t fill = ' ')
: AlignSpec(width, fill), flags_(0), precision_(-1), type_(type) {}
+ template <typename... FormatSpecs>
+ explicit FormatSpec(FormatSpecs... specs)
+ : AlignSpec(0, ' '), flags_(0), precision_(-1), type_(0){
+ set(specs...);
+ }
+
bool flag(unsigned f) const { return (flags_ & f) != 0; }
int precision() const { return precision_; }
char type() const { return type_; }
@@ -1811,13 +1882,6 @@
TYPE value, unsigned width) { \
return IntFormatSpec<TYPE, AlignTypeSpec<0> >( \
value, AlignTypeSpec<0>(width, ' ')); \
-} \
- \
-template <typename Char> \
-inline IntFormatSpec<TYPE, AlignTypeSpec<0>, Char> pad( \
- TYPE value, unsigned width, Char fill) { \
- return IntFormatSpec<TYPE, AlignTypeSpec<0>, Char>( \
- value, AlignTypeSpec<0>(width, fill)); \
}
FMT_DEFINE_INT_FORMATTERS(int)
@@ -2226,6 +2290,17 @@
FMT_API void format_system_error(fmt::writer &out, int error_code,
fmt::StringRef message) FMT_NOEXCEPT;
+namespace internal {
+// Named format specifier.
+template <typename T>
+class named_format_spec {
+ public:
+ constexpr named_format_spec() {}
+};
+
+constexpr named_format_spec<unsigned> width;
+}
+
/**
\rst
This template provides operations for formatting and writing data into
@@ -2309,7 +2384,7 @@
CharPtr prepare_int_buffer(unsigned num_digits,
const Spec &spec, const char *prefix, unsigned prefix_size);
- // Formats an integer.
+ // Writes a formatted integer.
template <typename T, typename Spec>
void write_int(T value, Spec spec);
@@ -2449,6 +2524,12 @@
*this << IntFormatSpec<ULongLong>(value);
}
+ template <typename T, typename... FormatSpecs>
+ typename std::enable_if<std::is_integral<T>::value, void>::type
+ write(T value, FormatSpecs... specs) {
+ write_int(value, FormatSpec(specs...));
+ }
+
void write(double value) {
write_double(value, FormatSpec());
}