nicer code separation, cleanup logic, std::function type caster
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 5d255ea..f8b468c 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -22,7 +22,10 @@
 
 string(TOUPPER "${CMAKE_BUILD_TYPE}" U_CMAKE_BUILD_TYPE)
 if (UNIX)
-  set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -Wno-unsequenced")
+  set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
+  if (CMAKE_CXX_COMPILER_ID MATCHES "Clang")
+    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-unsequenced")
+  endif()
   if (NOT ${U_CMAKE_BUILD_TYPE} MATCHES DEBUG)
     set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fvisibility=hidden -flto")
   endif()
diff --git a/example/example2.cpp b/example/example2.cpp
index 08fdd06..c4a352e 100644
--- a/example/example2.cpp
+++ b/example/example2.cpp
@@ -9,6 +9,7 @@
 */
 
 #include "example.h"
+#include <pybind/stl.h>
 
 class Example2 {
 public:
diff --git a/example/example5.cpp b/example/example5.cpp
index 738f9f4..c601ed7 100644
--- a/example/example5.cpp
+++ b/example/example5.cpp
@@ -9,6 +9,7 @@
 */
 
 #include "example.h"
+#include <pybind/functional.h>
 
 
 class Pet {
@@ -73,6 +74,14 @@
     ex->callback(value);
 }
 
+void test_callback4(const std::function<int(int)> &func) {
+    cout << "func(43) = " << func(43)<< std::endl;
+}
+
+std::function<int(int)> test_callback5() {
+    return [](int i) { return i+1; };
+}
+
 void init_ex5(py::module &m) {
     py::class_<Pet> pet_class(m, "Pet");
     pet_class
@@ -89,6 +98,8 @@
     m.def("test_callback1", &test_callback1);
     m.def("test_callback2", &test_callback2);
     m.def("test_callback3", &test_callback3);
+    m.def("test_callback4", &test_callback4);
+    m.def("test_callback5", &test_callback5);
 
     py::class_<Example5>(m, "Example5")
         .def(py::init<py::object, int>());
diff --git a/example/example5.py b/example/example5.py
index b119de9..c645af2 100755
--- a/example/example5.py
+++ b/example/example5.py
@@ -22,6 +22,8 @@
 from example import test_callback1
 from example import test_callback2
 from example import test_callback3
+from example import test_callback4
+from example import test_callback5
 from example import Example5
 
 def func1():
@@ -43,3 +45,7 @@
 
 callback = MyCallback(3)
 test_callback3(callback, 4)
+
+test_callback4(lambda i: i+1)
+f = test_callback5()
+print("func(43) = %i" % f(43))
diff --git a/include/pybind/cast.h b/include/pybind/cast.h
index 3013047..c59fbcf 100644
--- a/include/pybind/cast.h
+++ b/include/pybind/cast.h
@@ -12,7 +12,6 @@
 
 #include <pybind/pytypes.h>
 #include <pybind/typeid.h>
-#include <map>
 #include <array>
 
 NAMESPACE_BEGIN(pybind)
@@ -167,14 +166,14 @@
 PYBIND_TYPE_CASTER_NUMBER(float, float, PyFloat_AsDouble, PyFloat_FromDouble)
 PYBIND_TYPE_CASTER_NUMBER(double, double, PyFloat_AsDouble, PyFloat_FromDouble)
 
-template <> class type_caster<detail::void_type> {
+template <> class type_caster<void_type> {
 public:
     bool load(PyObject *, bool) { return true; }
-    static PyObject *cast(detail::void_type, return_value_policy /* policy */, PyObject * /* parent */) {
+    static PyObject *cast(void_type, return_value_policy /* policy */, PyObject * /* parent */) {
         Py_INCREF(Py_None);
         return Py_None;
     }
-    PYBIND_TYPE_CASTER(detail::void_type, "None");
+    PYBIND_TYPE_CASTER(void_type, "None");
 };
 
 template <> class type_caster<bool> {
@@ -192,23 +191,6 @@
     PYBIND_TYPE_CASTER(bool, "bool");
 };
 
-template <typename T> class type_caster<std::complex<T>> {
-public:
-    bool load(PyObject *src, bool) {
-        Py_complex result = PyComplex_AsCComplex(src);
-        if (result.real == -1.0 && PyErr_Occurred()) {
-            PyErr_Clear();
-            return false;
-        }
-        value = std::complex<T>((T) result.real, (T) result.imag);
-        return true;
-    }
-    static PyObject *cast(const std::complex<T> &src, return_value_policy /* policy */, PyObject * /* parent */) {
-        return PyComplex_FromDoubles((double) src.real(), (double) src.imag());
-    }
-    PYBIND_TYPE_CASTER(std::complex<T>, "complex");
-};
-
 template <> class type_caster<std::string> {
 public:
     bool load(PyObject *src, bool) {
@@ -265,83 +247,6 @@
     char *value;
 };
 
-template <typename Value> struct type_caster<std::vector<Value>> {
-    typedef std::vector<Value> type;
-    typedef type_caster<Value> value_conv;
-public:
-    bool load(PyObject *src, bool convert) {
-        if (!PyList_Check(src))
-            return false;
-        size_t size = (size_t) PyList_GET_SIZE(src);
-        value.reserve(size);
-        value.clear();
-        for (size_t i=0; i<size; ++i) {
-            value_conv conv;
-            if (!conv.load(PyList_GetItem(src, (ssize_t) i), convert))
-                return false;
-            value.push_back((Value) conv);
-        }
-        return true;
-    }
-
-    static PyObject *cast(const type &src, return_value_policy policy, PyObject *parent) {
-        PyObject *list = PyList_New(src.size());
-        size_t index = 0;
-        for (auto const &value: src) {
-            PyObject *value_ = value_conv::cast(value, policy, parent);
-            if (!value_) {
-                Py_DECREF(list);
-                return nullptr;
-            }
-            PyList_SetItem(list, index++, value_);
-        }
-        return list;
-    }
-    PYBIND_TYPE_CASTER(type, "list<" + value_conv::name() + ">");
-};
-
-template <typename Key, typename Value> struct type_caster<std::map<Key, Value>> {
-public:
-    typedef std::map<Key, Value>  type;
-    typedef type_caster<Key>   key_conv;
-    typedef type_caster<Value> value_conv;
-
-    bool load(PyObject *src, bool convert) {
-        if (!PyDict_Check(src))
-            return false;
-
-        value.clear();
-        PyObject *key_, *value_;
-        ssize_t pos = 0;
-        key_conv kconv;
-        value_conv vconv;
-        while (PyDict_Next(src, &pos, &key_, &value_)) {
-            if (!kconv.load(key_, convert) || !vconv.load(value_, convert))
-                return false;
-            value[kconv] = vconv;
-        }
-        return true;
-    }
-
-    static PyObject *cast(const type &src, return_value_policy policy, PyObject *parent) {
-        PyObject *dict = PyDict_New();
-        for (auto const &kv: src) {
-            PyObject *key   = key_conv::cast(kv.first, policy, parent);
-            PyObject *value = value_conv::cast(kv.second, policy, parent);
-            if (!key || !value || PyDict_SetItem(dict, key, value) < 0) {
-                Py_XDECREF(key);
-                Py_XDECREF(value);
-                Py_DECREF(dict);
-                return nullptr;
-            }
-            Py_DECREF(key);
-            Py_DECREF(value);
-        }
-        return dict;
-    }
-    PYBIND_TYPE_CASTER(type, "dict<" + key_conv::name() + ", " + value_conv::name() + ">");
-};
-
 template <typename T1, typename T2> class type_caster<std::pair<T1, T2>> {
     typedef std::pair<T1, T2> type;
 public:
@@ -354,8 +259,8 @@
     }
 
     static PyObject *cast(const type &src, return_value_policy policy, PyObject *parent) {
-        PyObject *o1 = type_caster<typename detail::decay<T1>::type>::cast(src.first, policy, parent);
-        PyObject *o2 = type_caster<typename detail::decay<T2>::type>::cast(src.second, policy, parent);
+        PyObject *o1 = type_caster<typename decay<T1>::type>::cast(src.first, policy, parent);
+        PyObject *o2 = type_caster<typename decay<T2>::type>::cast(src.second, policy, parent);
         if (!o1 || !o2) {
             Py_XDECREF(o1);
             Py_XDECREF(o2);
@@ -375,11 +280,11 @@
         return type(first, second);
     }
 protected:
-    type_caster<typename detail::decay<T1>::type> first;
-    type_caster<typename detail::decay<T2>::type> second;
+    type_caster<typename decay<T1>::type> first;
+    type_caster<typename decay<T2>::type> second;
 };
 
-template <typename ... Tuple> class type_caster<std::tuple<Tuple...>> {
+template <typename... Tuple> class type_caster<std::tuple<Tuple...>> {
     typedef std::tuple<Tuple...> type;
 public:
     enum { size = sizeof...(Tuple) };
@@ -394,7 +299,7 @@
 
     static std::string name(const char **keywords = nullptr, const char **values = nullptr) {
         std::array<std::string, size> names {{
-            type_caster<typename detail::decay<Tuple>::type>::name()...
+            type_caster<typename decay<Tuple>::type>::name()...
         }};
         std::string result("(");
         int counter = 0;
@@ -419,9 +324,9 @@
         return call<ReturnValue>(std::forward<Func>(f), typename make_index_sequence<sizeof...(Tuple)>::type());
     }
 
-    template <typename ReturnValue, typename Func> typename std::enable_if<std::is_void<ReturnValue>::value, detail::void_type>::type call(Func &&f) {
+    template <typename ReturnValue, typename Func> typename std::enable_if<std::is_void<ReturnValue>::value, void_type>::type call(Func &&f) {
         call<ReturnValue>(std::forward<Func>(f), typename make_index_sequence<sizeof...(Tuple)>::type());
-        return detail::void_type();
+        return void_type();
     }
 
     operator type() {
@@ -443,8 +348,9 @@
         if (PyTuple_Size(src) != size)
             return false;
         std::array<bool, size> results {{
-            std::get<Indices>(value).load(PyTuple_GetItem(src, Indices), convert)...
+            (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 */
         for (bool r : results)
             if (!r)
                 return false;
@@ -454,7 +360,7 @@
     /* Implementation: Convert a C++ tuple into a Python tuple */
     template <size_t ... Indices> static PyObject *cast(const type &src, return_value_policy policy, PyObject *parent, index_sequence<Indices...>) {
         std::array<PyObject *, size> results {{
-            type_caster<typename detail::decay<Tuple>::type>::cast(std::get<Indices>(src), policy, parent)...
+            type_caster<typename decay<Tuple>::type>::cast(std::get<Indices>(src), policy, parent)...
         }};
         bool success = true;
         for (auto result : results)
@@ -475,7 +381,7 @@
     }
 
 protected:
-    std::tuple<type_caster<typename detail::decay<Tuple>::type>...> value;
+    std::tuple<type_caster<typename decay<Tuple>::type>...> value;
 };
 
 /// Type caster for holder types like std::shared_ptr, etc.
@@ -542,7 +448,7 @@
 
 template <typename T> inline T handle::cast() { return pybind::cast<T>(m_ptr); }
 
-template <typename ... Args> inline object handle::call(Args&&... args_) {
+template <typename... Args> inline object handle::call(Args&&... args_) {
     const size_t size = sizeof...(Args);
     std::array<PyObject *, size> args{
         { detail::type_caster<typename detail::decay<Args>::type>::cast(
diff --git a/include/pybind/common.h b/include/pybind/common.h
index e4a7d34..0ee2668 100644
--- a/include/pybind/common.h
+++ b/include/pybind/common.h
@@ -31,9 +31,7 @@
 #include <string>
 #include <stdexcept>
 #include <unordered_map>
-#include <iostream>
 #include <memory>
-#include <complex>
 
 /// Include Python header, disable linking to pythonX_d.lib on Windows in debug mode
 #if defined(_MSC_VER)
@@ -46,6 +44,15 @@
 #endif
 #endif
 #include <Python.h>
+#ifdef isalnum
+#undef isalnum
+#undef isalpha
+#undef islower
+#undef isspace
+#undef isupper
+#undef tolower
+#undef toupper
+#endif
 #if defined(_MSC_VER)
 #if defined(_DEBUG_MARKER)
 #define _DEBUG
@@ -79,12 +86,10 @@
 
 /// Format strings for basic number types
 template <typename type> struct format_descriptor { };
-#define DECL_FMT(t, n) template<> struct format_descriptor<t> { static std::string value() { return n; }; };
-DECL_FMT(int8_t,  "b"); DECL_FMT(uint8_t,  "B"); DECL_FMT(int16_t, "h"); DECL_FMT(uint16_t, "H");
-DECL_FMT(int32_t, "i"); DECL_FMT(uint32_t, "I"); DECL_FMT(int64_t, "q"); DECL_FMT(uint64_t, "Q");
-DECL_FMT(float,   "f"); DECL_FMT(double,   "d"); DECL_FMT(bool,    "?");
-DECL_FMT(std::complex<float>, "Zf"); DECL_FMT(std::complex<double>, "Zd");
-#undef DECL_FMT
+#define PYBIND_DECL_FMT(t, n) template<> struct format_descriptor<t> { static std::string value() { return n; }; };
+PYBIND_DECL_FMT(int8_t,  "b"); PYBIND_DECL_FMT(uint8_t,  "B"); PYBIND_DECL_FMT(int16_t, "h"); PYBIND_DECL_FMT(uint16_t, "H");
+PYBIND_DECL_FMT(int32_t, "i"); PYBIND_DECL_FMT(uint32_t, "I"); PYBIND_DECL_FMT(int64_t, "q"); PYBIND_DECL_FMT(uint64_t, "Q");
+PYBIND_DECL_FMT(float,   "f"); PYBIND_DECL_FMT(double,   "d"); PYBIND_DECL_FMT(bool,    "?");
 
 /// Information record describing a Python buffer object
 struct buffer_info {
@@ -162,5 +167,6 @@
 
 /// Helper type to replace 'void' in some expressions
 struct void_type { };
+
 NAMESPACE_END(detail)
 NAMESPACE_END(pybind)
diff --git a/include/pybind/complex.h b/include/pybind/complex.h
new file mode 100644
index 0000000..9d690b1
--- /dev/null
+++ b/include/pybind/complex.h
@@ -0,0 +1,40 @@
+/*
+    pybind/complex.h: Complex number support
+
+    Copyright (c) 2015 Wenzel Jakob <wenzel@inf.ethz.ch>
+
+    All rights reserved. Use of this source code is governed by a
+    BSD-style license that can be found in the LICENSE file.
+*/
+
+#pragma once
+
+#include <pybind/pybind.h>
+#include <complex>
+
+NAMESPACE_BEGIN(pybind)
+
+PYBIND_DECL_FMT(std::complex<float>, "Zf");
+PYBIND_DECL_FMT(std::complex<double>, "Zd");
+
+NAMESPACE_BEGIN(detail)
+template <typename T> class type_caster<std::complex<T>> {
+public:
+    bool load(PyObject *src, bool) {
+        Py_complex result = PyComplex_AsCComplex(src);
+        if (result.real == -1.0 && PyErr_Occurred()) {
+            PyErr_Clear();
+            return false;
+        }
+        value = std::complex<T>((T) result.real, (T) result.imag);
+        return true;
+    }
+
+    static PyObject *cast(const std::complex<T> &src, return_value_policy /* policy */, PyObject * /* parent */) {
+        return PyComplex_FromDoubles((double) src.real(), (double) src.imag());
+    }
+
+    PYBIND_TYPE_CASTER(std::complex<T>, "complex");
+};
+NAMESPACE_END(detail)
+NAMESPACE_END(pybind)
diff --git a/include/pybind/functional.h b/include/pybind/functional.h
new file mode 100644
index 0000000..1979dea
--- /dev/null
+++ b/include/pybind/functional.h
@@ -0,0 +1,45 @@
+/*
+    pybind/functional.h: std::function<> support
+
+    Copyright (c) 2015 Wenzel Jakob <wenzel@inf.ethz.ch>
+
+    All rights reserved. Use of this source code is governed by a
+    BSD-style license that can be found in the LICENSE file.
+*/
+
+#pragma once
+
+#include <pybind/pybind.h>
+#include <functional>
+
+NAMESPACE_BEGIN(pybind)
+NAMESPACE_BEGIN(detail)
+
+template <typename Return, typename... Args> struct type_caster<std::function<Return(Args...)>> {
+    typedef std::function<Return(Args...)> type;
+public:
+
+    bool load(PyObject *src_, bool) {
+        if (!PyFunction_Check(src_))
+            return false;
+        object src(src_, true);
+        value = [src](Args... args) -> Return {
+            object retval(pybind::handle(src).call<Args...>(std::move(args)...));
+            /* Visual studio 2015 parser issue: need parentheses around this expression */
+            return (retval.template cast<Return>());
+        };
+        return true;
+    }
+
+    template <typename Func>
+    static PyObject *cast(Func &&f_, return_value_policy policy, PyObject *) {
+        cpp_function f(std::forward<Func>(f_), policy);
+        f.inc_ref();
+        return f.ptr();
+    }
+
+    PYBIND_TYPE_CASTER(type, "function<" + type_caster<std::tuple<Args...>>::name() + " -> " + type_caster<typename decay<Return>::type>::name() + ">");
+};
+
+NAMESPACE_END(detail)
+NAMESPACE_END(pybind)
diff --git a/include/pybind/numpy.h b/include/pybind/numpy.h
index 3c06854..d101013 100644
--- a/include/pybind/numpy.h
+++ b/include/pybind/numpy.h
@@ -10,7 +10,7 @@
 #pragma once
 
 #include <pybind/pybind.h>
-#include <functional>
+#include <pybind/complex.h>
 
 #if defined(_MSC_VER)
 #pragma warning(push)
@@ -126,6 +126,8 @@
     array_dtype() : array() { }
     static bool is_non_null(PyObject *ptr) { return ptr != nullptr; }
     PyObject *ensure(PyObject *ptr) {
+        if (ptr == nullptr)
+            return nullptr;
         API &api = lookup_api();
         PyObject *descr = api.PyArray_DescrFromType(npy_format_descriptor<T>::value);
         return api.PyArray_FromAny(ptr, descr, 0, 0,
@@ -158,7 +160,8 @@
 struct vectorize_helper {
     typename std::remove_reference<Func>::type f;
 
-    vectorize_helper(const Func &f) : f(f) { }
+    template <typename T>
+    vectorize_helper(T&&f) : f(std::forward<T>(f)) { }
 
     object operator()(array_dtype<Args>... args) {
         return run(args..., typename make_index_sequence<sizeof...(Args)>::type());
diff --git a/include/pybind/pybind.h b/include/pybind/pybind.h
index 64ae5a0..de496fb 100644
--- a/include/pybind/pybind.h
+++ b/include/pybind/pybind.h
@@ -16,9 +16,15 @@
 #pragma warning(disable: 4996) // warning C4996: The POSIX name for this item is deprecated. Instead, use the ISO C and C++ conformant name
 #pragma warning(disable: 4100) // warning C4100: Unreferenced formal parameter
 #pragma warning(disable: 4512) // warning C4512: Assignment operator was implicitly defined as deleted
+#elif defined(__GNUG__)
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wunused-but-set-parameter"
+#pragma GCC diagnostic ignored "-Wunused-but-set-variable"
+#pragma GCC diagnostic ignored "-Wmissing-field-initializers"
 #endif
 
 #include <pybind/cast.h>
+#include <iostream>
 
 NAMESPACE_BEGIN(pybind)
 
@@ -57,7 +63,8 @@
     struct function_entry {
         const char *name = nullptr;
         PyObject * (*impl) (function_entry *, PyObject *, PyObject *, PyObject *);
-        void *data;
+        PyMethodDef *def;
+        void *data = nullptr;
         bool is_constructor = false, is_method = false;
         short keywords = 0;
         return_value_policy policy = return_value_policy::automatic;
@@ -304,6 +311,17 @@
         }
     }
 
+    static void destruct(function_entry *entry) {
+        while (entry) {
+            delete entry->def;
+            operator delete(entry->data);
+            Py_XDECREF(entry->sibling);
+            function_entry *next = entry->next;
+            delete entry;
+            entry = next;
+        }
+    }
+
     void initialize(function_entry *entry, int args) {
         if (entry->name == nullptr)
             entry->name = "";
@@ -316,13 +334,13 @@
         entry->is_constructor = !strcmp(entry->name, "__init__");
 
         if (!entry->sibling || !PyCFunction_Check(entry->sibling)) {
-            PyMethodDef *def = new PyMethodDef();
-            memset(def, 0, sizeof(PyMethodDef));
-            def->ml_name = entry->name;
-            def->ml_meth = reinterpret_cast<PyCFunction>(*dispatcher);
-            def->ml_flags = METH_VARARGS | METH_KEYWORDS;
-            capsule entry_capsule(entry);
-            m_ptr = PyCFunction_New(def, entry_capsule.ptr());
+            entry->def = new PyMethodDef();
+            memset(entry->def, 0, sizeof(PyMethodDef));
+            entry->def->ml_name = entry->name;
+            entry->def->ml_meth = reinterpret_cast<PyCFunction>(*dispatcher);
+            entry->def->ml_flags = METH_VARARGS | METH_KEYWORDS;
+            capsule entry_capsule(entry, [](PyObject *o) { destruct((function_entry *) PyCapsule_GetPointer(o, nullptr)); });
+            m_ptr = PyCFunction_New(entry->def, entry_capsule.ptr());
             if (!m_ptr)
                 throw std::runtime_error("cpp_function::cpp_function(): Could not allocate function object");
         } else {
@@ -335,6 +353,7 @@
             parent->next = entry;
             entry = backup;
         }
+
         std::string signatures;
         int index = 0;
         function_entry *it = entry;
@@ -799,4 +818,7 @@
 
 #if defined(_MSC_VER)
 #pragma warning(pop)
+#elif defined(__GNUG__)
+#pragma GCC diagnostic pop
 #endif
+
diff --git a/include/pybind/pytypes.h b/include/pybind/pytypes.h
index 2586a8b..2a9052f 100644
--- a/include/pybind/pytypes.h
+++ b/include/pybind/pytypes.h
@@ -217,7 +217,6 @@
 };
 
 inline pybind::str handle::str() const { return pybind::str(PyObject_Str(m_ptr), false); }
-inline std::ostream &operator<<(std::ostream &os, const object &obj) { os << (const char *) obj.str(); return os; }
 
 class bool_ : public object {
 public:
@@ -258,7 +257,8 @@
 class capsule : public object {
 public:
     PYBIND_OBJECT_DEFAULT(capsule, object, PyCapsule_CheckExact)
-    capsule(void *value) : object(PyCapsule_New(value, nullptr, nullptr), false) { }
+    capsule(PyObject *obj, bool borrowed) : object(obj, borrowed) { }
+    capsule(void *value, void (*destruct)(PyObject *) = nullptr) : object(PyCapsule_New(value, nullptr, destruct), false) { }
     template <typename T> operator T *() const {
         T * result = static_cast<T *>(PyCapsule_GetPointer(m_ptr, nullptr));
         if (!result) throw std::runtime_error("Unable to extract capsule contents!");
diff --git a/include/pybind/stl.h b/include/pybind/stl.h
new file mode 100644
index 0000000..90c583b
--- /dev/null
+++ b/include/pybind/stl.h
@@ -0,0 +1,109 @@
+/*
+    pybind/complex.h: Complex number support
+
+    Copyright (c) 2015 Wenzel Jakob <wenzel@inf.ethz.ch>
+
+    All rights reserved. Use of this source code is governed by a
+    BSD-style license that can be found in the LICENSE file.
+*/
+
+#pragma once
+
+#include <pybind/pybind.h>
+#include <map>
+#include <iostream>
+
+
+#if defined(_MSC_VER)
+#pragma warning(push)
+#pragma warning(disable: 4127) // warning C4127: Conditional expression is constant
+#endif
+
+NAMESPACE_BEGIN(pybind)
+NAMESPACE_BEGIN(detail)
+
+template <typename Value> struct type_caster<std::vector<Value>> {
+    typedef std::vector<Value> type;
+    typedef type_caster<Value> value_conv;
+public:
+    bool load(PyObject *src, bool convert) {
+        if (!PyList_Check(src))
+            return false;
+        size_t size = (size_t) PyList_GET_SIZE(src);
+        value.reserve(size);
+        value.clear();
+        for (size_t i=0; i<size; ++i) {
+            value_conv conv;
+            if (!conv.load(PyList_GetItem(src, (ssize_t) i), convert))
+                return false;
+            value.push_back((Value) conv);
+        }
+        return true;
+    }
+
+    static PyObject *cast(const type &src, return_value_policy policy, PyObject *parent) {
+        PyObject *list = PyList_New(src.size());
+        size_t index = 0;
+        for (auto const &value: src) {
+            PyObject *value_ = value_conv::cast(value, policy, parent);
+            if (!value_) {
+                Py_DECREF(list);
+                return nullptr;
+            }
+            PyList_SetItem(list, index++, value_);
+        }
+        return list;
+    }
+    PYBIND_TYPE_CASTER(type, "list<" + value_conv::name() + ">");
+};
+
+template <typename Key, typename Value> struct type_caster<std::map<Key, Value>> {
+public:
+    typedef std::map<Key, Value>  type;
+    typedef type_caster<Key>   key_conv;
+    typedef type_caster<Value> value_conv;
+
+    bool load(PyObject *src, bool convert) {
+        if (!PyDict_Check(src))
+            return false;
+
+        value.clear();
+        PyObject *key_, *value_;
+        ssize_t pos = 0;
+        key_conv kconv;
+        value_conv vconv;
+        while (PyDict_Next(src, &pos, &key_, &value_)) {
+            if (!kconv.load(key_, convert) || !vconv.load(value_, convert))
+                return false;
+            value[kconv] = vconv;
+        }
+        return true;
+    }
+
+    static PyObject *cast(const type &src, return_value_policy policy, PyObject *parent) {
+        PyObject *dict = PyDict_New();
+        for (auto const &kv: src) {
+            PyObject *key   = key_conv::cast(kv.first, policy, parent);
+            PyObject *value = value_conv::cast(kv.second, policy, parent);
+            if (!key || !value || PyDict_SetItem(dict, key, value) < 0) {
+                Py_XDECREF(key);
+                Py_XDECREF(value);
+                Py_DECREF(dict);
+                return nullptr;
+            }
+            Py_DECREF(key);
+            Py_DECREF(value);
+        }
+        return dict;
+    }
+    PYBIND_TYPE_CASTER(type, "dict<" + key_conv::name() + ", " + value_conv::name() + ">");
+};
+
+inline std::ostream &operator<<(std::ostream &os, const object &obj) { os << (const char *) obj.str(); return os; }
+
+NAMESPACE_END(detail)
+NAMESPACE_END(pybind)
+
+#if defined(_MSC_VER)
+#pragma warning(pop)
+#endif
diff --git a/tools/mkdoc.py b/tools/mkdoc.py
index 4f47575..d1b61c9 100644
--- a/tools/mkdoc.py
+++ b/tools/mkdoc.py
@@ -212,7 +212,13 @@
 #define __DOC3(n1, n2, n3)                       __doc_##n1##_##n2##_##n3
 #define __DOC4(n1, n2, n3, n4)                   __doc_##n1##_##n2##_##n3##_##n4
 #define __DOC5(n1, n2, n3, n4, n5)               __doc_##n1##_##n2##_##n3##_##n4_##n5
-#define DOC(...)                                 __CAT2(__DOC, __VA_SIZE(__VA_ARGS__))(__VA_ARGS__)''')
+#define DOC(...)                                 __CAT2(__DOC, __VA_SIZE(__VA_ARGS__))(__VA_ARGS__)
+
+#if defined(__GNUG__)
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wunused-variable"
+#endif
+''')
 
     output = []
     for filename in filenames:
@@ -226,3 +232,9 @@
     output.sort()
     for l in output:
         print(l)
+
+    print('''
+#if defined(__GNUG__)
+#pragma GCC diagnostic pop
+#endif
+''')