Refactor argument visitor API (#422)
diff --git a/fmt/format.h b/fmt/format.h
index 848d79a..0eb1f45 100644
--- a/fmt/format.h
+++ b/fmt/format.h
@@ -1536,7 +1536,8 @@
 #define FMT_DISPATCH(call) static_cast<Impl*>(this)->call
 
 template <typename Visitor>
-typename std::result_of<Visitor(int)>::type visit(Visitor &&vis, format_arg arg) {
+typename std::result_of<Visitor(int)>::type visit(Visitor &&vis,
+                                                  format_arg arg) {
   switch (arg.type) {
   case format_arg::NONE:
   case format_arg::NAMED_ARG:
@@ -1746,7 +1747,9 @@
     called.
     \endrst
    */
-  Result visit(const format_arg &arg) { return fmt::visit(*this, arg); }
+  Result visit(const format_arg &arg) {
+    return fmt::visit(*static_cast<Impl*>(this), arg);
+  }
 };
 
 enum Alignment {
@@ -2056,6 +2059,22 @@
     writer_.write_int(reinterpret_cast<uintptr_t>(p), spec_);
   }
 
+  template <typename StrChar>
+  void write_str(Arg::StringValue<StrChar> value,
+                  typename EnableIf<
+                    std::is_same<Char, wchar_t>::value &&
+                    std::is_same<StrChar, wchar_t>::value, int>::type = 0) {
+    writer_.write_str(value, spec_);
+  }
+
+  template <typename StrChar>
+  void write_str(Arg::StringValue<StrChar> value,
+                  typename EnableIf<
+                    !std::is_same<Char, wchar_t>::value ||
+                    !std::is_same<StrChar, wchar_t>::value, int>::type = 0) {
+    // Do nothing.
+  }
+
  protected:
   BasicWriter<Char> &writer() { return writer_; }
   FormatSpec &spec() { return spec_; }
@@ -2083,13 +2102,15 @@
   template <typename T>
   void visit_any_double(T value) { writer_.write_double(value, spec_); }
 
-  void visit_bool(bool value) {
+  using ArgVisitor<Impl, void>::operator();
+
+  void operator()(bool value) {
     if (spec_.type_)
       return visit_any_int(value);
     write(value);
   }
 
-  void visit_char(int value) {
+  void operator()(wchar_t value) {
     if (spec_.type_ && spec_.type_ != 'c') {
       spec_.flags_ |= CHAR_FLAG;
       writer_.write_int(value, spec_);
@@ -2119,23 +2140,21 @@
     *out = internal::CharTraits<Char>::cast(value);
   }
 
-  void visit_cstring(const char *value) {
+  void operator()(const char *value) {
     if (spec_.type_ == 'p')
       return write_pointer(value);
     write(value);
   }
 
-  void visit_string(Arg::StringValue<char> value) {
+  void operator()(Arg::StringValue<char> value) {
     writer_.write_str(value, spec_);
   }
 
-  using ArgVisitor<Impl, void>::visit_wstring;
-
-  void visit_wstring(Arg::StringValue<Char> value) {
-    writer_.write_str(value, spec_);
+  void operator()(Arg::StringValue<wchar_t> value) {
+    write_str(value);
   }
 
-  void visit_pointer(const void *value) {
+  void operator()(const void *value) {
     if (spec_.type_ && spec_.type_ != 'p')
       report_unknown_type(spec_.type_, "pointer");
     write_pointer(value);
diff --git a/fmt/printf.h b/fmt/printf.h
index 85572c4..8f9278f 100644
--- a/fmt/printf.h
+++ b/fmt/printf.h
@@ -210,8 +210,10 @@
   BasicPrintfArgFormatter(BasicWriter<Char> &writer, FormatSpec &spec)
   : internal::ArgFormatterBase<Impl, Char>(writer, spec) {}
 
+  using Base::operator();
+
   /** Formats an argument of type ``bool``. */
-  void visit_bool(bool value) {
+  void operator()(bool value) {
     FormatSpec &fmt_spec = this->spec();
     if (fmt_spec.type_ != 's')
       return this->visit_any_int(value);
@@ -220,7 +222,7 @@
   }
 
   /** Formats a character. */
-  void visit_char(int value) {
+  void operator()(wchar_t value) {
     const FormatSpec &fmt_spec = this->spec();
     BasicWriter<Char> &w = this->writer();
     if (fmt_spec.type_ && fmt_spec.type_ != 'c')
@@ -243,9 +245,9 @@
   }
 
   /** Formats a null-terminated C string. */
-  void visit_cstring(const char *value) {
+  void operator()(const char *value) {
     if (value)
-      Base::visit_cstring(value);
+      Base::operator()(value);
     else if (this->spec().type_ == 'p')
       write_null_pointer();
     else
@@ -253,15 +255,15 @@
   }
 
   /** Formats a pointer. */
-  void visit_pointer(const void *value) {
+  void operator()(const void *value) {
     if (value)
-      return Base::visit_pointer(value);
+      return Base::operator()(value);
     this->spec().type_ = 0;
     write_null_pointer();
   }
 
   /** Formats an argument of a custom (user-defined) type. */
-  void visit_custom(internal::Arg::CustomValue c) {
+  void operator()(internal::Arg::CustomValue c) {
     const Char format_str[] = {'}', '\0'};
     auto args = basic_format_args<basic_format_context<Char>>();
     basic_format_context<Char> ctx(format_str, args);