Don't erase writer type
diff --git a/fmt/format.h b/fmt/format.h
index dc8ce0c..723e539 100644
--- a/fmt/format.h
+++ b/fmt/format.h
@@ -1089,9 +1089,11 @@
   std::size_t size;
 };
 
-typedef void (*FormatFunc)(void *writer, const void *arg, void *ctx);
-
+template <typename Char>
 struct CustomValue {
+  typedef void (*FormatFunc)(
+      BasicWriter<Char> &writer, const void *arg, void *ctx);
+
   const void *value;
   FormatFunc format;
 };
@@ -1111,7 +1113,7 @@
     StringValue<signed char> sstring;
     StringValue<unsigned char> ustring;
     StringValue<Char> tstring;
-    CustomValue custom;
+    CustomValue<Char> custom;
   };
 };
 
@@ -1216,9 +1218,8 @@
   // Formats an argument of a custom type, such as a user-defined class.
   template <typename T>
   static void format_custom_arg(
-      void *writer, const void *arg, void *context) {
-    format_value(*static_cast<BasicWriter<Char>*>(writer),
-                 *static_cast<const T*>(arg),
+      BasicWriter<Char> &writer, const void *arg, void *context) {
+    format_value(writer, *static_cast<const T*>(arg),
                  *static_cast<Context*>(context));
   }
 
@@ -2140,8 +2141,8 @@
   using internal::ArgFormatterBase<Char>::operator();
 
   /** Formats an argument of a custom (user-defined) type. */
-  void operator()(internal::CustomValue c) {
-    c.format(&this->writer(), c.value, &ctx_);
+  void operator()(internal::CustomValue<Char> c) {
+    c.format(this->writer(), c.value, &ctx_);
   }
 };
 
@@ -3371,8 +3372,8 @@
   CustomFormatter(BasicWriter<Char> &writer, Context &ctx)
   : writer_(writer), ctx_(ctx) {}
 
-  bool operator()(internal::CustomValue custom) {
-    custom.format(&writer_, custom.value, &ctx_);
+  bool operator()(internal::CustomValue<Char> custom) {
+    custom.format(writer_, custom.value, &ctx_);
     return true;
   }
 
diff --git a/fmt/printf.h b/fmt/printf.h
index c0064ae..92d50ef 100644
--- a/fmt/printf.h
+++ b/fmt/printf.h
@@ -281,11 +281,11 @@
   }
 
   /** Formats an argument of a custom (user-defined) type. */
-  void operator()(internal::CustomValue c) {
+  void operator()(internal::CustomValue<Char> c) {
     const Char format_str[] = {'}', '\0'};
     auto args = basic_format_args<basic_format_context<Char>, Char>();
     basic_format_context<Char> ctx(format_str, args);
-    c.format(&this->writer(), c.value, &ctx);
+    c.format(this->writer(), c.value, &ctx);
   }
 };
 
diff --git a/test/format-test.cc b/test/format-test.cc
index 6829f62..b8693d5 100644
--- a/test/format-test.cc
+++ b/test/format-test.cc
@@ -1637,7 +1637,7 @@
 
   void operator()(int value) { call(value); }
 
-  void operator()(fmt::internal::CustomValue) {}
+  void operator()(fmt::internal::CustomValue<char>) {}
 };
 
 void custom_vformat(fmt::CStringRef format_str, fmt::format_args args) {
diff --git a/test/util-test.cc b/test/util-test.cc
index e02b68d..0e276d5 100644
--- a/test/util-test.cc
+++ b/test/util-test.cc
@@ -426,14 +426,15 @@
   fmt::internal::Value<char> arg = fmt::internal::MakeValue<CustomFormatter>(t);
   CustomFormatter ctx = {false};
   fmt::MemoryWriter w;
-  arg.custom.format(&w, &t, &ctx);
+  arg.custom.format(w, &t, &ctx);
   EXPECT_TRUE(ctx.called);
 }
 
 namespace fmt {
 namespace internal {
 
-bool operator==(CustomValue lhs, CustomValue rhs) {
+template <typename Char>
+bool operator==(CustomValue<Char> lhs, CustomValue<Char> rhs) {
   return lhs.value == rhs.value;
 }
 }
@@ -563,14 +564,14 @@
 
 TEST(UtilTest, CustomArg) {
   ::Test test;
-  typedef MockVisitor<fmt::internal::CustomValue> Visitor;
+  typedef MockVisitor<fmt::internal::CustomValue<char>> Visitor;
   testing::StrictMock<Visitor> visitor;
   EXPECT_CALL(visitor, visit(_)).WillOnce(
-        testing::Invoke([&](fmt::internal::CustomValue custom) {
+        testing::Invoke([&](fmt::internal::CustomValue<char> custom) {
     EXPECT_EQ(&test, custom.value);
     fmt::MemoryWriter w;
     fmt::format_context ctx("}", fmt::format_args());
-    custom.format(&w, &test, &ctx);
+    custom.format(w, &test, &ctx);
     EXPECT_EQ("test", w.str());
     return Visitor::Result();
   }));