factored out some common functionality to a non-templated parent class
diff --git a/include/pybind11/cast.h b/include/pybind11/cast.h
index a813252..a6f45ef 100644
--- a/include/pybind11/cast.h
+++ b/include/pybind11/cast.h
@@ -18,12 +18,6 @@
 NAMESPACE_BEGIN(pybind11)
 NAMESPACE_BEGIN(detail)
 
-#if defined(_MSC_VER)
-#define NOINLINE __declspec(noinline)
-#else
-#define NOINLINE __attribute__ ((noinline))
-#endif
-
 #if PY_MAJOR_VERSION >= 3
 #define PYBIND11_AS_STRING PyBytes_AsString
 #else
@@ -44,35 +38,35 @@
 
     descr() { }
     descr(descr &&d) : first(d.first), last(d.last) { d.first = d.last = nullptr; }
-    NOINLINE descr(const char *str) { first = last = new entry { str }; }
-    NOINLINE descr(const std::type_info &type) { first = last = new entry { &type }; }
+    PYBIND11_NOINLINE descr(const char *str) { first = last = new entry { str }; }
+    PYBIND11_NOINLINE descr(const std::type_info &type) { first = last = new entry { &type }; }
 
-    NOINLINE void operator+(const char *str) {
+    PYBIND11_NOINLINE void operator+(const char *str) {
         entry *next = new entry { str };
         last->next = next;
         last = next;
     }
 
-    NOINLINE void operator+(const std::type_info *type) {
+    PYBIND11_NOINLINE void operator+(const std::type_info *type) {
         entry *next = new entry { type };
         last->next = next;
         last = next;
     }
 
-    NOINLINE void operator+=(descr &&other) {
+    PYBIND11_NOINLINE void operator+=(descr &&other) {
         last->next = other.first;
         while (last->next)
             last = last->next;
         other.first = other.last = nullptr;
     }
 
-    NOINLINE friend descr operator+(descr &&l, descr &&r) {
+    PYBIND11_NOINLINE friend descr operator+(descr &&l, descr &&r) {
         descr result(std::move(l));
         result += std::move(r);
         return result;
     }
 
-    NOINLINE std::string str() const {
+    PYBIND11_NOINLINE std::string str() const {
         std::string result;
         auto const& registered_types = get_internals().registered_types;
         for (entry *it = first; it != nullptr; it = it->next) {
@@ -92,7 +86,7 @@
         return result;
     }
 
-    NOINLINE ~descr() {
+    PYBIND11_NOINLINE ~descr() {
         while (first) {
             entry *tmp = first->next;
             delete first;
@@ -104,27 +98,20 @@
     entry *last = nullptr;
 };
 
-#undef NOINLINE
-
-/// Generic type caster for objects stored on the heap
-template <typename type> class type_caster {
+class type_caster_custom {
 public:
-    typedef instance<type> instance_type;
-
-    static descr name() { return typeid(type); }
-
-    type_caster() {
+    PYBIND11_NOINLINE type_caster_custom(const std::type_info *type_info) {
         auto const& registered_types = get_internals().registered_types;
-        auto it = registered_types.find(&typeid(type));
+        auto it = registered_types.find(type_info);
         if (it != registered_types.end())
             typeinfo = &it->second;
     }
 
-    bool load(PyObject *src, bool convert) {
+    PYBIND11_NOINLINE bool load(PyObject *src, bool convert) {
         if (src == nullptr || typeinfo == nullptr)
             return false;
         if (PyType_IsSubtype(Py_TYPE(src), typeinfo->type)) {
-            value = ((instance_type *) src)->value;
+            value = ((instance<void> *) src)->value;
             return true;
         }
         if (convert) {
@@ -137,14 +124,9 @@
         return false;
     }
 
-    static PyObject *cast(const type &src, return_value_policy policy, PyObject *parent) {
-        if (policy == return_value_policy::automatic)
-            policy = return_value_policy::copy;
-        return cast(&src, policy, parent);
-    }
-
-    static PyObject *cast(const type *_src, return_value_policy policy, PyObject *parent) {
-        type *src = const_cast<type *>(_src);
+    PYBIND11_NOINLINE static PyObject *cast(const void *_src, return_value_policy policy, PyObject *parent,
+                                            const std::type_info *type_info, void *(*copy_constructor)(const void *)) {
+        void *src = const_cast<void *>(_src);
         if (src == nullptr) {
             Py_INCREF(Py_None);
             return Py_None;
@@ -159,61 +141,72 @@
             Py_INCREF(inst);
             return inst;
         }
-        auto it = internals.registered_types.find(&typeid(type));
+        auto it = internals.registered_types.find(type_info);
         if (it == internals.registered_types.end()) {
-            std::string msg = std::string("Unregistered type : ") + type_id<type>();
+            std::string msg = std::string("Unregistered type : ") + type_info->name();
+            detail::clean_type_id(msg);
             PyErr_SetString(PyExc_TypeError, msg.c_str());
             return nullptr;
         }
-        auto &type_info = it->second;
-        instance_type *inst = (instance_type *) PyType_GenericAlloc(type_info.type, 0);
+        auto &reg_type = it->second;
+        instance<void> *inst = (instance<void> *) PyType_GenericAlloc(reg_type.type, 0);
         inst->value = src;
         inst->owned = true;
         inst->parent = nullptr;
         if (policy == return_value_policy::automatic)
             policy = return_value_policy::take_ownership;
-        handle_return_value_policy<type>(inst, policy, parent);
+        if (policy == return_value_policy::copy) {
+            inst->value = copy_constructor(inst->value);
+            if (inst->value == nullptr)
+                throw cast_error("return_value_policy = copy, but the object is non-copyable!");
+        } else if (policy == return_value_policy::reference) {
+            inst->owned = false;
+        } else if (policy == return_value_policy::reference_internal) {
+            inst->owned = false;
+            inst->parent = parent;
+            Py_XINCREF(parent);
+        }
         PyObject *inst_pyobj = (PyObject *) inst;
-        type_info.init_holder(inst_pyobj);
+        reg_type.init_holder(inst_pyobj);
         if (!dont_cache)
             internals.registered_instances[inst->value] = inst_pyobj;
         return inst_pyobj;
     }
 
-    template <class T, typename std::enable_if<std::is_copy_constructible<T>::value, int>::type = 0>
-    static void handle_return_value_policy(instance<T> *inst, return_value_policy policy, PyObject *parent) {
-        if (policy == return_value_policy::copy) {
-            inst->value = new T(*(inst->value));
-        } else if (policy == return_value_policy::reference) {
-            inst->owned = false;
-        } else if (policy == return_value_policy::reference_internal) {
-            inst->owned = false;
-            inst->parent = parent;
-            Py_XINCREF(parent);
-        }
-    }
-
-    template <class T, typename std::enable_if<!std::is_copy_constructible<T>::value, int>::type = 0>
-    static void handle_return_value_policy(instance<T> *inst, return_value_policy policy, PyObject *parent) {
-        if (policy == return_value_policy::copy) {
-            throw cast_error("return_value_policy = copy, but the object is non-copyable!");
-        } else if (policy == return_value_policy::reference) {
-            inst->owned = false;
-        } else if (policy == return_value_policy::reference_internal) {
-            inst->owned = false;
-            inst->parent = parent;
-            Py_XINCREF(parent);
-        }
-    }
-
-    operator type*() { return value; }
-    operator type&() { return *value; }
 protected:
-    type *value = nullptr;
     const type_info *typeinfo = nullptr;
+    void *value = nullptr;
     object temp;
 };
 
+/// Generic type caster for objects stored on the heap
+template <typename type> class type_caster : public type_caster_custom {
+public:
+    static descr name() { return typeid(type); }
+
+    type_caster() : type_caster_custom(&typeid(type)) { }
+
+    static PyObject *cast(const type &src, return_value_policy policy, PyObject *parent) {
+        if (policy == return_value_policy::automatic)
+            policy = return_value_policy::copy;
+        return type_caster_custom::cast(&src, policy, parent, &typeid(type), &copy_constructor);
+    }
+
+    static PyObject *cast(const type *src, return_value_policy policy, PyObject *parent) {
+        return type_caster_custom::cast(src, policy, parent, &typeid(type), &copy_constructor);
+    }
+
+    operator type*() { return (type *) value; }
+    operator type&() { return (type &) *value; }
+protected:
+    template <typename T = type, typename std::enable_if<std::is_copy_constructible<T>::value, int>::type = 0>
+    static void *copy_constructor(const void *arg) {
+        return new type((const type &)*arg);
+    }
+    template <typename T = type, typename std::enable_if<!std::is_copy_constructible<T>::value, int>::type = 0>
+    static void *copy_constructor(const void *) { return nullptr; }
+};
+
 #define PYBIND11_TYPE_CASTER(type, py_name) \
     protected: \
         type value; \
@@ -516,7 +509,7 @@
     bool load(PyObject *src, bool convert) {
         if (!parent::load(src, convert))
             return false;
-        holder = holder_type(parent::value);
+        holder = holder_type((type *) parent::value);
         return true;
     }
     explicit operator type*() { return this->value; }
diff --git a/include/pybind11/common.h b/include/pybind11/common.h
index bfa8c4a..0bbf5ee 100644
--- a/include/pybind11/common.h
+++ b/include/pybind11/common.h
@@ -23,6 +23,12 @@
 #define PYBIND11_EXPORT __attribute__ ((visibility("default")))
 #endif
 #endif
+#if defined(_MSC_VER)
+#define PYBIND11_NOINLINE __declspec(noinline)
+#else
+#define PYBIND11_NOINLINE __attribute__ ((noinline))
+#endif
+
 
 #include <vector>
 #include <string>