Replace filed instance transformations with functiors for better readability.
diff --git a/src/field_instance.h b/src/field_instance.h
index 5545ffa..eb72e78 100644
--- a/src/field_instance.h
+++ b/src/field_instance.h
@@ -190,6 +190,9 @@
   size_t index() const { return index_; }
 
  private:
+  template <class Fn, class T>
+  friend struct FieldFunction;
+
   const protobuf::Message* message_;
   const protobuf::FieldDescriptor* descriptor_;
   size_t index_;
@@ -301,37 +304,6 @@
     if (value) mutable_message->CopyFrom(*value);
   }
 
-  template <class Transformation>
-  void Apply(const Transformation& transformation) const {
-    assert(descriptor());
-    using protobuf::FieldDescriptor;
-    switch (cpp_type()) {
-      case FieldDescriptor::CPPTYPE_INT32:
-        return transformation.template Apply<int32_t>(*this);
-      case FieldDescriptor::CPPTYPE_INT64:
-        return transformation.template Apply<int64_t>(*this);
-      case FieldDescriptor::CPPTYPE_UINT32:
-        return transformation.template Apply<uint32_t>(*this);
-      case FieldDescriptor::CPPTYPE_UINT64:
-        return transformation.template Apply<uint64_t>(*this);
-      case FieldDescriptor::CPPTYPE_DOUBLE:
-        return transformation.template Apply<double>(*this);
-      case FieldDescriptor::CPPTYPE_FLOAT:
-        return transformation.template Apply<float>(*this);
-      case FieldDescriptor::CPPTYPE_BOOL:
-        return transformation.template Apply<bool>(*this);
-      case FieldDescriptor::CPPTYPE_ENUM:
-        return transformation.template Apply<FieldInstance::Enum>(*this);
-      case FieldDescriptor::CPPTYPE_STRING:
-        return transformation.template Apply<std::string>(*this);
-      case FieldDescriptor::CPPTYPE_MESSAGE:
-        return transformation
-            .template Apply<std::unique_ptr<protobuf::Message>>(*this);
-      default:
-        assert(!"Unknown type");
-    }
-  }
-
  private:
   template <class T>
   void InsertRepeated(const T& value) const {
@@ -404,6 +376,50 @@
   protobuf::Message* message_;
 };
 
+template <class Fn, class R = void>
+struct FieldFunction {
+  template <class Field, class... Args>
+  R operator()(const Field& field, const Args&... args) const {
+    assert(field.descriptor());
+    using protobuf::FieldDescriptor;
+    switch (field.cpp_type()) {
+      case FieldDescriptor::CPPTYPE_INT32:
+        return static_cast<const Fn*>(this)->template ForType<int32_t>(field,
+                                                                       args...);
+      case FieldDescriptor::CPPTYPE_INT64:
+        return static_cast<const Fn*>(this)->template ForType<int64_t>(field,
+                                                                       args...);
+      case FieldDescriptor::CPPTYPE_UINT32:
+        return static_cast<const Fn*>(this)->template ForType<uint32_t>(
+            field, args...);
+      case FieldDescriptor::CPPTYPE_UINT64:
+        return static_cast<const Fn*>(this)->template ForType<uint64_t>(
+            field, args...);
+      case FieldDescriptor::CPPTYPE_DOUBLE:
+        return static_cast<const Fn*>(this)->template ForType<double>(field,
+                                                                      args...);
+      case FieldDescriptor::CPPTYPE_FLOAT:
+        return static_cast<const Fn*>(this)->template ForType<float>(field,
+                                                                     args...);
+      case FieldDescriptor::CPPTYPE_BOOL:
+        return static_cast<const Fn*>(this)->template ForType<bool>(field,
+                                                                    args...);
+      case FieldDescriptor::CPPTYPE_ENUM:
+        return static_cast<const Fn*>(this)
+            ->template ForType<ConstFieldInstance::Enum>(field, args...);
+      case FieldDescriptor::CPPTYPE_STRING:
+        return static_cast<const Fn*>(this)->template ForType<std::string>(
+            field, args...);
+      case FieldDescriptor::CPPTYPE_MESSAGE:
+        return static_cast<const Fn*>(this)
+            ->template ForType<std::unique_ptr<protobuf::Message>>(field,
+                                                                   args...);
+      default:
+        assert(!"Unknown type");
+    }
+  }
+};
+
 }  // namespace protobuf_mutator
 
 #endif  // SRC_FIELD_INSTANCE_H_
diff --git a/src/protobuf_mutator.cc b/src/protobuf_mutator.cc
index e63cee6..29eb699 100644
--- a/src/protobuf_mutator.cc
+++ b/src/protobuf_mutator.cc
@@ -78,48 +78,40 @@
   return GetRandomIndex(random, n) == 0;
 }
 
-struct CreateDefaultFieldTransformation {
+struct CreateDefaultField : public FieldFunction<CreateDefaultField> {
   template <class T>
-  void Apply(const FieldInstance& field) const {
+  void ForType(const FieldInstance& field) const {
     T value;
     field.GetDefault(&value);
     field.Create(value);
   }
 };
 
-struct DeleteFieldTransformation {
+struct DeleteField : public FieldFunction<DeleteField> {
   template <class T>
-  void Apply(const FieldInstance& field) const {
+  void ForType(const FieldInstance& field) const {
     field.Delete();
   }
 };
 
-struct CopyFieldTransformation {
-  explicit CopyFieldTransformation(const ConstFieldInstance& field)
-      : source(field) {}
-
+struct CopyField : public FieldFunction<CopyField> {
   template <class T>
-  void Apply(const FieldInstance& field) const {
+  void ForType(const ConstFieldInstance& source,
+               const FieldInstance& field) const {
     T value;
     source.Load(&value);
     field.Store(value);
   }
-
-  ConstFieldInstance source;
 };
 
-struct AppendFieldTransformation {
-  explicit AppendFieldTransformation(const ConstFieldInstance& field)
-      : source(field) {}
-
+struct AppendField : public FieldFunction<AppendField> {
   template <class T>
-  void Apply(const FieldInstance& field) const {
+  void ForType(const ConstFieldInstance& source,
+               const FieldInstance& field) const {
     T value;
     source.Load(&value);
     field.Create(value);
   }
-
-  ConstFieldInstance source;
 };
 
 // Selects random field and mutation from the given proto message.
@@ -380,38 +372,27 @@
 
 namespace {
 
-class MutateTransformation {
- public:
-  MutateTransformation(size_t size_increase_hint, ProtobufMutator* mutator)
-      : mutator_(size_increase_hint, mutator) {}
-
+struct MutateField : public FieldFunction<MutateField> {
   template <class T>
-  void Apply(const FieldInstance& field) const {
+  void ForType(const FieldInstance& field, size_t size_increase_hint,
+               ProtobufMutator* mutator) const {
     T value;
     field.Load(&value);
-    mutator_.Mutate(&value);
+    FieldMutator(size_increase_hint, mutator).Mutate(&value);
     field.Store(value);
   }
-
- private:
-  FieldMutator mutator_;
 };
 
-class CreateFieldTransformation {
+struct CreateField : public FieldFunction<CreateField> {
  public:
-  CreateFieldTransformation(size_t size_increase_hint, ProtobufMutator* mutator)
-      : mutator_(size_increase_hint, mutator) {}
-
   template <class T>
-  void Apply(const FieldInstance& field) const {
+  void ForType(const FieldInstance& field, size_t size_increase_hint,
+               ProtobufMutator* mutator) const {
     T value;
     field.GetDefault(&value);
-    mutator_.Mutate(&value);
+    FieldMutator(size_increase_hint, mutator).Mutate(&value);
     field.Create(value);
   }
-
- private:
-  FieldMutator mutator_;
 };
 
 }  // namespace
@@ -426,27 +407,25 @@
       break;
     case Mutation::Add:
       if (GetRandomBool(&random_)) {
-        mutation.field().Apply(
-            CreateFieldTransformation(size_increase_hint / 2, this));
+        CreateField()(mutation.field(), size_increase_hint / 2, this);
       } else {
-        mutation.field().Apply(CreateDefaultFieldTransformation());
+        CreateDefaultField()(mutation.field());
       }
       break;
     case Mutation::Mutate:
-      mutation.field().Apply(
-          MutateTransformation(size_increase_hint / 2, this));
+      MutateField()(mutation.field(), size_increase_hint / 2, this);
       break;
     case Mutation::Delete:
-      mutation.field().Apply(DeleteFieldTransformation());
+      DeleteField()(mutation.field());
       break;
     case Mutation::Copy: {
       DataSourceSampler source(mutation.field(), &random_, message);
       if (source.IsEmpty()) {
         // Fallback to message deletion.
-        mutation.field().Apply(DeleteFieldTransformation());
+        DeleteField()(mutation.field());
         break;
       }
-      mutation.field().Apply(CopyFieldTransformation(source.field()));
+      CopyField()(source.field(), mutation.field());
       break;
     }
     default:
@@ -485,7 +464,7 @@
       for (int j = 0; j < field_size1; ++j) {
         ConstFieldInstance source(&message1, field, j);
         FieldInstance destination(message2, field, field_size2++);
-        destination.Apply(AppendFieldTransformation(source));
+        AppendField()(source, destination);
       }
 
       assert(field_size2 == reflection->FieldSize(*message2, field));
@@ -519,11 +498,11 @@
     } else if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
       if (!reflection->HasField(message1, field)) {
         if (GetRandomBool(&random_))
-          FieldInstance(message2, field).Apply(DeleteFieldTransformation());
+          DeleteField()(FieldInstance(message2, field));
       } else if (!reflection->HasField(*message2, field)) {
         if (GetRandomBool(&random_)) {
           ConstFieldInstance source(&message1, field);
-          FieldInstance(message2, field).Apply(CopyFieldTransformation(source));
+          CopyField()(source, FieldInstance(message2, field));
         }
       } else {
         CrossOverImpl(reflection->GetMessage(message1, field),
@@ -533,9 +512,9 @@
       if (GetRandomBool(&random_)) {
         if (reflection->HasField(message1, field)) {
           ConstFieldInstance source(&message1, field);
-          FieldInstance(message2, field).Apply(CopyFieldTransformation(source));
+          CopyField()(source, FieldInstance(message2, field));
         } else {
-          FieldInstance(message2, field).Apply(DeleteFieldTransformation());
+          DeleteField()(FieldInstance(message2, field));
         }
       }
     }
@@ -552,7 +531,7 @@
   for (int i = 0; i < descriptor->field_count(); ++i) {
     const FieldDescriptor* field = descriptor->field(i);
     if (field->is_required() && !reflection->HasField(*message, field))
-      FieldInstance(message, field).Apply(CreateDefaultFieldTransformation());
+      CreateDefaultField()(FieldInstance(message, field));
 
     if (max_depth > 0 &&
         field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {