avoid std::string when creating signatures, and make nicer type names. binary size reduced by ~10%
diff --git a/include/pybind/cast.h b/include/pybind/cast.h
index c59fbcf..38b9d7f 100644
--- a/include/pybind/cast.h
+++ b/include/pybind/cast.h
@@ -17,16 +17,98 @@
 NAMESPACE_BEGIN(pybind)
 NAMESPACE_BEGIN(detail)
 
+#if defined(_MSC_VER)
+#define NOINLINE __declspec(noinline)
+#else
+#define NOINLINE __attribute__ ((noinline))
+#endif
+
+/** Linked list descriptor type for function signatures (produces smaller binaries
+ * compared to a previous solution using std::string and operator +=) */
+class descr {
+public:
+    struct entry {
+        const std::type_info *type = nullptr;
+        const char *str = nullptr;
+        entry *next = nullptr;
+        entry(const std::type_info *type) : type(type) { }
+        entry(const char *str) : str(str) { }
+    };
+
+    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 }; }
+
+    NOINLINE void operator+(const char *str) {
+        entry *next = new entry { str };
+        last->next = next;
+        last = next;
+    }
+
+    NOINLINE void operator+(const std::type_info *type) {
+        entry *next = new entry { type };
+        last->next = next;
+        last = next;
+    }
+
+    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) {
+        descr result(std::move(l));
+        result += std::move(r);
+        return result;
+    }
+
+    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) {
+            if (it->type) {
+                auto it2 = registered_types.find(it->type);
+                if (it2 != registered_types.end()) {
+                    result += it2->second.type->tp_name;
+                } else {
+                    std::string tname(it->type->name());
+                    detail::clean_type_id(tname);
+                    result += tname;
+                }
+            } else {
+                result += it->str;
+            }
+        }
+        return result;
+    }
+
+    NOINLINE ~descr() {
+        while (first) {
+            entry *tmp = first->next;
+            delete first;
+            first = tmp;
+        }
+    }
+
+    entry *first = nullptr;
+    entry *last = nullptr;
+};
+
+#undef NOINLINE
+
 /// Generic type caster for objects stored on the heap
 template <typename type> class type_caster {
 public:
     typedef instance<type> instance_type;
 
-    static std::string name() { return type_id<type>(); }
+    static descr descr() { return typeid(type); }
 
     type_caster() {
         auto const& registered_types = get_internals().registered_types;
-        auto it = registered_types.find(type_id<type>());
+        auto it = registered_types.find(&typeid(type));
         if (it != registered_types.end())
             typeinfo = &it->second;
     }
@@ -70,7 +152,7 @@
             Py_INCREF(inst);
             return inst;
         }
-        auto it = internals.registered_types.find(type_id<type>());
+        auto it = internals.registered_types.find(&typeid(type));
         if (it == internals.registered_types.end()) {
             std::string msg = std::string("Unregistered type : ") + type_id<type>();
             PyErr_SetString(PyExc_TypeError, msg.c_str());
@@ -129,7 +211,7 @@
     protected: \
         type value; \
     public: \
-        static std::string name() { return py_name; } \
+        static descr descr() { return py_name; } \
         static PyObject *cast(const type *src, return_value_policy policy, PyObject *parent) { \
             return cast(*src, policy, parent); \
         } \
@@ -239,7 +321,7 @@
         return PyUnicode_DecodeLatin1(str, 1, nullptr);
     }
 
-    static std::string name() { return "str"; }
+    static descr descr() { return "str"; }
 
     operator char*() { return value; }
     operator char() { return *value; }
@@ -272,8 +354,13 @@
         return tuple;
     }
 
-    static std::string name() {
-        return "(" + type_caster<T1>::name() + ", " + type_caster<T2>::name() + ")";
+    static descr descr() {
+        class descr result("(");
+        result += std::move(type_caster<typename decay<T1>::type>::descr());
+        result += ", ";
+        result += std::move(type_caster<typename decay<T2>::type>::descr());
+        result += ")";
+        return result;
     }
 
     operator type() {
@@ -297,23 +384,22 @@
         return cast(src, policy, parent, typename make_index_sequence<size>::type());
     }
 
-    static std::string name(const char **keywords = nullptr, const char **values = nullptr) {
-        std::array<std::string, size> names {{
-            type_caster<typename decay<Tuple>::type>::name()...
+    static descr descr(const char **keywords = nullptr, const char **values = nullptr) {
+        std::array<class descr, size> descrs {{
+            type_caster<typename decay<Tuple>::type>::descr()...
         }};
-        std::string result("(");
-        int counter = 0;
-        for (auto const &name : names) {
-            if (keywords && keywords[counter]) {
-                result += keywords[counter];
+        class descr result("(");
+        for (int i=0; i<size; ++i) {
+            if (keywords && keywords[i]) {
+                result += keywords[i];
                 result += " : ";
             }
-            result += name;
-            if (values && values[counter]) {
+            result += std::move(descrs[i]);
+            if (values && values[i]) {
                 result += " = ";
-                result += values[counter];
+                result += values[i];
             }
-            if (++counter < size)
+            if (i+1 < size)
                 result += ", ";
         }
         result += ")";
@@ -350,7 +436,7 @@
         std::array<bool, size> results {{
             (PyTuple_GET_ITEM(src, Indices) != nullptr ? std::get<Indices>(value).load(PyTuple_GET_ITEM(src, Indices), convert) : false)...
         }};
-	(void) convert; /* avoid a warning when the tuple is empty */
+        (void) convert; /* avoid a warning when the tuple is empty */
         for (bool r : results)
             if (!r)
                 return false;
diff --git a/include/pybind/common.h b/include/pybind/common.h
index 0ee2668..8a9850d 100644
--- a/include/pybind/common.h
+++ b/include/pybind/common.h
@@ -139,7 +139,7 @@
 
 /// Internal data struture used to track registered instances and types
 struct internals {
-    std::unordered_map<std::string, type_info> registered_types;
+    std::unordered_map<const std::type_info *, type_info> registered_types;
     std::unordered_map<void *, PyObject *> registered_instances;
 };
 
diff --git a/include/pybind/functional.h b/include/pybind/functional.h
index 1979dea..1eedab6 100644
--- a/include/pybind/functional.h
+++ b/include/pybind/functional.h
@@ -38,7 +38,11 @@
         return f.ptr();
     }
 
-    PYBIND_TYPE_CASTER(type, "function<" + type_caster<std::tuple<Args...>>::name() + " -> " + type_caster<typename decay<Return>::type>::name() + ">");
+
+    PYBIND_TYPE_CASTER(type, detail::descr("function<") +
+            type_caster<std::tuple<Args...>>::descr() + detail::descr(" -> ") +
+            type_caster<typename decay<Return>::type>::descr() +
+            detail::descr(">"));
 };
 
 NAMESPACE_END(detail)
diff --git a/include/pybind/pybind.h b/include/pybind/pybind.h
index ecf06db..dbf1290 100644
--- a/include/pybind/pybind.h
+++ b/include/pybind/pybind.h
@@ -189,11 +189,12 @@
         std::array<const char *, N> kw{}, def{};
         process_extras(((capture *) entry->data)->extras, entry, kw.data(), def.data());
 
-        entry->signature = cast_in::name(kw.data(), def.data());
-        entry->signature += " -> ";
-        entry->signature += cast_out::name();
 
-        initialize(entry, sizeof...(Arg));
+        detail::descr d = cast_in::descr(kw.data(), def.data());
+        d += " -> ";
+        d += std::move(cast_out::descr());
+
+        initialize(entry, d, sizeof...(Arg));
     }
 
     /// Delegating helper constructor to deal with lambda functions
@@ -246,11 +247,11 @@
         std::array<const char *, N> kw{}, def{};
         process_extras(((capture *) entry->data)->extras, entry, kw.data(), def.data());
 
-        entry->signature = cast_in::name(kw.data(), def.data());
-        entry->signature += " -> ";
-        entry->signature += cast_out::name();
+        detail::descr d = cast_in::descr(kw.data(), def.data());
+        d += " -> ";
+        d += std::move(cast_out::descr());
 
-        initialize(entry, sizeof...(Arg));
+        initialize(entry, d, sizeof...(Arg));
     }
 
     static PyObject *dispatcher(PyObject *self, PyObject *args, PyObject *kwargs ) {
@@ -322,9 +323,10 @@
         }
     }
 
-    void initialize(function_entry *entry, int args) {
+    void initialize(function_entry *entry, const detail::descr &descr, int args) {
         if (entry->name == nullptr)
             entry->name = "";
+
         if (entry->keywords != 0 && entry->keywords != args)
             throw std::runtime_error(
                 "cpp_function(): function \"" + std::string(entry->name) + "\" takes " +
@@ -332,6 +334,7 @@
                 " pybind::arg entries were specified!");
 
         entry->is_constructor = !strcmp(entry->name, "__init__");
+        entry->signature = descr.str();
 
         if (!entry->sibling || !PyCFunction_Check(entry->sibling)) {
             entry->def = new PyMethodDef();
@@ -423,7 +426,7 @@
 public:
     PYBIND_OBJECT_DEFAULT(custom_type, object, PyType_Check)
 
-    custom_type(object &scope, const char *name_, const std::string &type_name,
+    custom_type(object &scope, const char *name_, const std::type_info *tinfo,
                 size_t type_size, size_t instance_size,
                 void (*init_holder)(PyObject *), const destructor &dealloc,
                 PyObject *parent, const char *doc) {
@@ -465,7 +468,7 @@
         if (((module &) scope).check())
             attr("__module__") = scope_name;
 
-        auto &type_info = detail::get_internals().registered_types[type_name];
+        auto &type_info = detail::get_internals().registered_types[tinfo];
         type_info.type = (PyTypeObject *) m_ptr;
         type_info.type_size = type_size;
         type_info.init_holder = init_holder;
@@ -592,13 +595,13 @@
     PYBIND_OBJECT(class_, detail::custom_type, PyType_Check)
 
     class_(object &scope, const char *name, const char *doc = nullptr)
-        : detail::custom_type(scope, name, type_id<type>(), sizeof(type),
+        : detail::custom_type(scope, name, &typeid(type), sizeof(type),
                               sizeof(instance_type), init_holder, dealloc,
                               nullptr, doc) { }
 
     class_(object &scope, const char *name, object &parent,
            const char *doc = nullptr)
-        : detail::custom_type(scope, name, type_id<type>(), sizeof(type),
+        : detail::custom_type(scope, name, &typeid(type), sizeof(type),
                               sizeof(instance_type), init_holder, dealloc,
                               parent.ptr(), doc) { }
 
@@ -790,11 +793,10 @@
             PyErr_Clear();
         return result;
     };
-    std::string output_type_name = type_id<OutputType>();
     auto & registered_types = detail::get_internals().registered_types;
-    auto it = registered_types.find(output_type_name);
+    auto it = registered_types.find(&typeid(OutputType));
     if (it == registered_types.end())
-        throw std::runtime_error("implicitly_convertible: Unable to find type " + output_type_name);
+        throw std::runtime_error("implicitly_convertible: Unable to find type " + type_id<OutputType>());
     it->second.implicit_conversions.push_back(implicit_caster);
 }
 
diff --git a/include/pybind/stl.h b/include/pybind/stl.h
index 90c583b..36568a0 100644
--- a/include/pybind/stl.h
+++ b/include/pybind/stl.h
@@ -54,7 +54,7 @@
         }
         return list;
     }
-    PYBIND_TYPE_CASTER(type, "list<" + value_conv::name() + ">");
+    PYBIND_TYPE_CASTER(type, detail::descr("list<") + value_conv::descr() + detail::descr(">"));
 };
 
 template <typename Key, typename Value> struct type_caster<std::map<Key, Value>> {
@@ -96,7 +96,8 @@
         }
         return dict;
     }
-    PYBIND_TYPE_CASTER(type, "dict<" + key_conv::name() + ", " + value_conv::name() + ">");
+
+    PYBIND_TYPE_CASTER(type, detail::descr("dict<") + key_conv::descr() + detail::descr(", ") + value_conv::descr() + detail::descr(">"));
 };
 
 inline std::ostream &operator<<(std::ostream &os, const object &obj) { os << (const char *) obj.str(); return os; }