redesigned format_descriptor<> and npy_format_descriptor<>

This somewhat heavyweight solution will avoid size_t/long long/long/int
mismatches on various platforms once and for all. The previous template
overloads could e.g. not handle size_t on Darwin.

One gotcha: the 'format_descriptor<T>::value()' syntax changed to just
'format_descriptor<T>::value'
diff --git a/docs/advanced.rst b/docs/advanced.rst
index e8ce71f..ec09534 100644
--- a/docs/advanced.rst
+++ b/docs/advanced.rst
@@ -825,12 +825,12 @@
     py::class_<Matrix>(m, "Matrix")
        .def_buffer([](Matrix &m) -> py::buffer_info {
             return py::buffer_info(
-                m.data(),                              /* Pointer to buffer */
-                sizeof(float),                         /* Size of one scalar */
-                py::format_descriptor<float>::value(), /* Python struct-style format descriptor */
-                2,                                     /* Number of dimensions */
-                { m.rows(), m.cols() },                /* Buffer dimensions */
-                { sizeof(float) * m.rows(),            /* Strides (in bytes) for each index */
+                m.data(),                            /* Pointer to buffer */
+                sizeof(float),                       /* Size of one scalar */
+                py::format_descriptor<float>::value, /* Python struct-style format descriptor */
+                2,                                   /* Number of dimensions */
+                { m.rows(), m.cols() },              /* Buffer dimensions */
+                { sizeof(float) * m.rows(),          /* Strides (in bytes) for each index */
                   sizeof(float) }
             );
         });
@@ -867,7 +867,7 @@
             py::buffer_info info = b.request();
 
             /* Some sanity checks ... */
-            if (info.format != py::format_descriptor<double>::value())
+            if (info.format != py::format_descriptor<double>::value)
                 throw std::runtime_error("Incompatible format: expected a double array!");
 
             if (info.ndim != 2)
@@ -994,7 +994,7 @@
         auto result = py::array(py::buffer_info(
             nullptr,            /* Pointer to data (nullptr -> ask NumPy to allocate!) */
             sizeof(double),     /* Size of one item */
-            py::format_descriptor<double>::value(), /* Buffer format */
+            py::format_descriptor<double>::value, /* Buffer format */
             buf1.ndim,          /* How many dimensions? */
             { buf1.shape[0] },  /* Number of elements for each dimension */
             { sizeof(double) }  /* Strides for each dimension */
diff --git a/example/example7.cpp b/example/example7.cpp
index 415b097..6aabf1c 100644
--- a/example/example7.cpp
+++ b/example/example7.cpp
@@ -80,7 +80,7 @@
         /// Construct from a buffer
         .def("__init__", [](Matrix &v, py::buffer b) {
             py::buffer_info info = b.request();
-            if (info.format != py::format_descriptor<float>::value() || info.ndim != 2)
+            if (info.format != py::format_descriptor<float>::value || info.ndim != 2)
                 throw std::runtime_error("Incompatible buffer format!");
             new (&v) Matrix(info.shape[0], info.shape[1]);
             memcpy(v.data(), info.ptr, sizeof(float) * v.rows() * v.cols());
@@ -103,12 +103,12 @@
        /// Provide buffer access
        .def_buffer([](Matrix &m) -> py::buffer_info {
             return py::buffer_info(
-                m.data(),                              /* Pointer to buffer */
-                sizeof(float),                         /* Size of one scalar */
-                py::format_descriptor<float>::value(), /* Python struct-style format descriptor */
-                2,                                     /* Number of dimensions */
-                { m.rows(), m.cols() },                /* Buffer dimensions */
-                { sizeof(float) * m.rows(),            /* Strides (in bytes) for each index */
+                m.data(),                            /* Pointer to buffer */
+                sizeof(float),                       /* Size of one scalar */
+                py::format_descriptor<float>::value, /* Python struct-style format descriptor */
+                2,                                   /* Number of dimensions */
+                { m.rows(), m.cols() },              /* Buffer dimensions */
+                { sizeof(float) * m.rows(),          /* Strides (in bytes) for each index */
                   sizeof(float) }
             );
         });
diff --git a/include/pybind11/common.h b/include/pybind11/common.h
index abf764a..1ca0d1d 100644
--- a/include/pybind11/common.h
+++ b/include/pybind11/common.h
@@ -191,13 +191,6 @@
     reference_internal
 };
 
-/// Format strings for basic number types
-template <typename type> struct format_descriptor { };
-#define PYBIND11_DECL_FMT(t, n) template<> struct format_descriptor<t> { static std::string value() { return n; }; }
-PYBIND11_DECL_FMT(int8_t,  "b"); PYBIND11_DECL_FMT(uint8_t,  "B"); PYBIND11_DECL_FMT(int16_t, "h"); PYBIND11_DECL_FMT(uint16_t, "H");
-PYBIND11_DECL_FMT(int32_t, "i"); PYBIND11_DECL_FMT(uint32_t, "I"); PYBIND11_DECL_FMT(int64_t, "q"); PYBIND11_DECL_FMT(uint64_t, "Q");
-PYBIND11_DECL_FMT(float,   "f"); PYBIND11_DECL_FMT(double,   "d"); PYBIND11_DECL_FMT(bool,    "?");
-
 /// Information record describing a Python buffer object
 struct buffer_info {
     void *ptr;                   // Pointer to the underlying storage
@@ -234,6 +227,8 @@
 
 NAMESPACE_BEGIN(detail)
 
+static constexpr int log2(size_t n, int k = 0) { return (n <= 1) ? k : log2(n >> 1, k + 1); }
+
 inline std::string error_string();
 
 /// Core part of the 'instance' type which POD (needed to be able to use 'offsetof')
@@ -296,13 +291,6 @@
 /// Helper type to replace 'void' in some expressions
 struct void_type { };
 
-/// to_string variant which also accepts strings
-template <typename T> inline typename std::enable_if<!std::is_enum<T>::value, std::string>::type
-to_string(const T &value) { return std::to_string(value); }
-template <> inline std::string to_string(const std::string &value) { return value; }
-template <typename T> inline typename std::enable_if<std::is_enum<T>::value, std::string>::type
-to_string(T value) { return std::to_string((int) value); }
-
 NAMESPACE_END(detail)
 
 #define PYBIND11_RUNTIME_EXCEPTION(name) \
@@ -321,4 +309,15 @@
 [[noreturn]] PYBIND11_NOINLINE inline void pybind11_fail(const char *reason) { throw std::runtime_error(reason); }
 [[noreturn]] PYBIND11_NOINLINE inline void pybind11_fail(const std::string &reason) { throw std::runtime_error(reason); }
 
+/// Format strings for basic number types
+#define PYBIND11_DECL_FMT(t, v) template<> struct format_descriptor<t> { static constexpr const char *value = v; }
+template <typename T, typename SFINAE = void> struct format_descriptor { };
+template <typename T> struct format_descriptor<T, typename std::enable_if<std::is_integral<T>::value>::type> {
+    static constexpr const char value[2] =
+        { "bBhHiIqQ"[detail::log2(sizeof(T))*2 + (std::is_unsigned<T>::value ? 1 : 0)], '\0' };
+};
+template <typename T> constexpr const char format_descriptor<
+    T, typename std::enable_if<std::is_integral<T>::value>::type>::value[2];
+PYBIND11_DECL_FMT(float, "f"); PYBIND11_DECL_FMT(double, "d"); PYBIND11_DECL_FMT(bool, "?");
+
 NAMESPACE_END(pybind11)
diff --git a/include/pybind11/numpy.h b/include/pybind11/numpy.h
index 38d30bf..cf46c33 100644
--- a/include/pybind11/numpy.h
+++ b/include/pybind11/numpy.h
@@ -21,7 +21,7 @@
 
 NAMESPACE_BEGIN(pybind11)
 
-template <typename type> struct npy_format_descriptor { };
+template <typename type, typename SFINAE = void> struct npy_format_descriptor { };
 
 class array : public buffer {
 public:
@@ -138,12 +138,20 @@
     }
 };
 
+template <typename T> struct npy_format_descriptor<T, typename std::enable_if<std::is_integral<T>::value>::type> {
+private:
+    constexpr static const int values[] = {
+        array::API::NPY_BYTE_, array::API::NPY_UBYTE_, array::API::NPY_SHORT_,    array::API::NPY_USHORT_,
+        array::API::NPY_INT_,  array::API::NPY_UINT_,  array::API::NPY_LONGLONG_, array::API::NPY_ULONGLONG_ };
+public:
+    enum { value = values[detail::log2(sizeof(T)) * 2 + (std::is_unsigned<T>::value ? 1 : 0)] };
+};
+template <typename T> constexpr const int npy_format_descriptor<
+    T, typename std::enable_if<std::is_integral<T>::value>::type>::values[8];
+
 #define DECL_FMT(t, n) template<> struct npy_format_descriptor<t> { enum { value = array::API::n }; }
-DECL_FMT(int8_t, NPY_BYTE_);  DECL_FMT(uint8_t, NPY_UBYTE_); DECL_FMT(int16_t, NPY_SHORT_);
-DECL_FMT(uint16_t, NPY_USHORT_); DECL_FMT(int32_t, NPY_INT_); DECL_FMT(uint32_t, NPY_UINT_);
-DECL_FMT(int64_t, NPY_LONGLONG_); DECL_FMT(uint64_t, NPY_ULONGLONG_); DECL_FMT(float, NPY_FLOAT_);
-DECL_FMT(double, NPY_DOUBLE_); DECL_FMT(bool, NPY_BOOL_); DECL_FMT(std::complex<float>, NPY_CFLOAT_);
-DECL_FMT(std::complex<double>, NPY_CDOUBLE_);
+DECL_FMT(float, NPY_FLOAT_); DECL_FMT(double, NPY_DOUBLE_); DECL_FMT(bool, NPY_BOOL_);
+DECL_FMT(std::complex<float>, NPY_CFLOAT_); DECL_FMT(std::complex<double>, NPY_CDOUBLE_);
 #undef DECL_FMT
 
 NAMESPACE_BEGIN(detail)
@@ -328,7 +336,7 @@
             return cast(f(*((Args *) buffers[Index].ptr)...));
 
         array result(buffer_info(nullptr, sizeof(Return),
-            format_descriptor<Return>::value(),
+            format_descriptor<Return>::value,
             ndim, shape, strides));
 
         buffer_info buf = result.request();