Allow passing base types as a template parameter

This allows a slightly cleaner base type specification of:

    py::class_<Type, Base>("Type")

as an alternative to

    py::class_<Type>("Type", py::base<Base>())

As with the other template parameters, the order relative to the holder
or trampoline types doesn't matter.

This also includes a compile-time assertion failure if attempting to
specify more than one base class (but is easily extendible to support
multiple inheritance, someday, by updating the class_selector::set_bases
function to set multiple bases).
diff --git a/docs/advanced.rst b/docs/advanced.rst
index 6a4a020..748f91e 100644
--- a/docs/advanced.rst
+++ b/docs/advanced.rst
@@ -1227,7 +1227,7 @@
     the other existing exception translators.
 
     The ``py::exception`` wrapper for creating custom exceptions cannot (yet)
-    be used as a ``py::base``.
+    be used as a base type.
 
 .. _eigen:
 
@@ -1811,16 +1811,17 @@
         .def(py::init<const std::string &>())
         .def("bark", &Dog::bark);
 
-Alternatively, we can rely on the ``base`` tag, which performs an automated
-lookup of the corresponding Python type. However, this also requires invoking
-the ``import`` function once to ensure that the pybind11 binding code of the
-module ``basic`` has been executed.
+Alternatively, you can specify the base class as a template parameter option to
+``class_``, which performs an automated lookup of the corresponding Python
+type. Like the above code, however, this also requires invoking the ``import``
+function once to ensure that the pybind11 binding code of the module ``basic``
+has been executed:
 
 .. code-block:: cpp
 
     py::module::import("basic");
 
-    py::class_<Dog>(m, "Dog", py::base<Pet>())
+    py::class_<Dog, Pet>(m, "Dog")
         .def(py::init<const std::string &>())
         .def("bark", &Dog::bark);
 
diff --git a/docs/classes.rst b/docs/classes.rst
index 5afb21e..80f378f 100644
--- a/docs/classes.rst
+++ b/docs/classes.rst
@@ -185,9 +185,10 @@
         std::string bark() const { return "woof!"; }
     };
 
-There are two different ways of indicating a hierarchical relationship to
-pybind11: the first is by specifying the C++ base class explicitly during
-construction using the ``base`` attribute:
+There are three different ways of indicating a hierarchical relationship to
+pybind11: the first specifies the C++ base class as an extra template
+parameter of the :class:`class_`; the second uses a special ``base`` attribute
+passed into the constructor:
 
 .. code-block:: cpp
 
@@ -195,6 +196,12 @@
        .def(py::init<const std::string &>())
        .def_readwrite("name", &Pet::name);
 
+    // Method 1: template parameter:
+    py::class_<Dog, Pet /* <- specify C++ parent type */>(m, "Dog")
+        .def(py::init<const std::string &>())
+        .def("bark", &Dog::bark);
+
+    // Method 2: py::base attribute:
     py::class_<Dog>(m, "Dog", py::base<Pet>() /* <- specify C++ parent type */)
         .def(py::init<const std::string &>())
         .def("bark", &Dog::bark);
@@ -208,11 +215,12 @@
     pet.def(py::init<const std::string &>())
        .def_readwrite("name", &Pet::name);
 
+    // Method 3: pass parent class_ object:
     py::class_<Dog>(m, "Dog", pet /* <- specify Python parent type */)
         .def(py::init<const std::string &>())
         .def("bark", &Dog::bark);
 
-Functionality-wise, both approaches are completely equivalent. Afterwards,
+Functionality-wise, all three approaches are completely equivalent. Afterwards,
 instances will expose fields and methods of both types:
 
 .. code-block:: pycon
diff --git a/include/pybind11/cast.h b/include/pybind11/cast.h
index e5579e1..f6d86e3 100644
--- a/include/pybind11/cast.h
+++ b/include/pybind11/cast.h
@@ -798,12 +798,12 @@
     holder_type holder;
 };
 
+// PYBIND11_DECLARE_HOLDER_TYPE holder types:
 template <typename base, typename holder> struct is_holder_type :
-    // PYBIND11_DECLARE_HOLDER_TYPE holder types:
-    std::conditional<std::is_base_of<detail::type_caster_holder<base, holder>, detail::type_caster<holder>>::value,
-    std::true_type,
-    std::false_type>::type {};
-template <typename base, typename deleter> struct is_holder_type<base, std::unique_ptr<base, deleter>> : std::true_type {};
+    std::is_base_of<detail::type_caster_holder<base, holder>, detail::type_caster<holder>> {};
+// Specialization for always-supported unique_ptr holders:
+template <typename base, typename deleter> struct is_holder_type<base, std::unique_ptr<base, deleter>> :
+    std::true_type {};
 
 template <typename T> struct handle_type_name { static PYBIND11_DESCR name() { return _<T>(); } };
 template <> struct handle_type_name<bytes> { static PYBIND11_DESCR name() { return _(PYBIND11_BYTES_NAME); } };
diff --git a/include/pybind11/common.h b/include/pybind11/common.h
index 6aeeb3d..c086e87 100644
--- a/include/pybind11/common.h
+++ b/include/pybind11/common.h
@@ -358,20 +358,20 @@
 struct any_of_t<P, T, Ts...> : conditional_t<P<T>::value, std::true_type, any_of_t<P, Ts...>> { };
 #endif
 
-// Extracts the first type from the template parameter pack matching the predicate, or void if none match.
-template <template<class> class Predicate, class... Ts> struct first_of;
-template <template<class> class Predicate> struct first_of<Predicate> {
-    using type = void;
+// Extracts the first type from the template parameter pack matching the predicate, or Default if none match.
+template <template<class> class Predicate, class Default, class... Ts> struct first_of;
+template <template<class> class Predicate, class Default> struct first_of<Predicate, Default> {
+    using type = Default;
 };
-template <template<class> class Predicate, class T, class... Ts>
-struct first_of<Predicate, T, Ts...> {
+template <template<class> class Predicate, class Default, class T, class... Ts>
+struct first_of<Predicate, Default, T, Ts...> {
     using type = typename std::conditional<
         Predicate<T>::value,
         T,
-        typename first_of<Predicate, Ts...>::type
+        typename first_of<Predicate, Default, Ts...>::type
     >::type;
 };
-template <template<class> class Predicate, class... T> using first_of_t = typename first_of<Predicate, T...>::type;
+template <template<class> class Predicate, class Default, class... T> using first_of_t = typename first_of<Predicate, Default, T...>::type;
 
 // Counts the number of types in the template parameter pack matching the predicate
 template <template<typename> class Predicate, typename... Ts> struct count_t;
diff --git a/include/pybind11/pybind11.h b/include/pybind11/pybind11.h
index 3f04ba5..0d16c7a 100644
--- a/include/pybind11/pybind11.h
+++ b/include/pybind11/pybind11.h
@@ -802,34 +802,47 @@
 
     static void releasebuffer(PyObject *, Py_buffer *view) { delete (buffer_info *) view->internal; }
 };
+
+template <template<typename> class Predicate, typename... BaseTypes> struct class_selector;
+template <template<typename> class Predicate, typename Base, typename... Bases>
+struct class_selector<Predicate, Base, Bases...> {
+    static inline void set_bases(detail::type_record &record) {
+        if (Predicate<Base>::value) record.base_type = &typeid(Base);
+        else class_selector<Predicate, Bases...>::set_bases(record);
+    }
+};
+template <template<typename> class Predicate>
+struct class_selector<Predicate> {
+    static inline void set_bases(detail::type_record &) {}
+};
+
 NAMESPACE_END(detail)
 
 template <typename type_, typename... options>
 class class_ : public detail::generic_type {
     template <typename T> using is_holder = detail::is_holder_type<type_, T>;
     template <typename T> using is_subtype = detail::bool_constant<std::is_base_of<type_, T>::value && !std::is_same<T, type_>::value>;
+    template <typename T> using is_base_class = detail::bool_constant<std::is_base_of<T, type_>::value && !std::is_same<T, type_>::value>;
     template <typename T> using is_valid_class_option =
         detail::bool_constant<
             is_holder<T>::value ||
-            is_subtype<T>::value
+            is_subtype<T>::value ||
+            is_base_class<T>::value
         >;
 
-    using extracted_holder_t = typename detail::first_of_t<is_holder, options...>;
-
 public:
     using type = type_;
-    using type_alias = detail::first_of_t<is_subtype, options...>;
+    using type_alias = detail::first_of_t<is_subtype, void, options...>;
     constexpr static bool has_alias = !std::is_void<type_alias>::value;
-    using holder_type = typename std::conditional<
-        std::is_void<extracted_holder_t>::value,
-        std::unique_ptr<type>,
-        extracted_holder_t
-    >::type;
+    using holder_type = detail::first_of_t<is_holder, std::unique_ptr<type>, options...>;
     using instance_type = detail::instance<type, holder_type>;
 
     static_assert(detail::all_of_t<is_valid_class_option, options...>::value,
             "Unknown/invalid class_ template parameters provided");
 
+    static_assert(detail::count_t<is_base_class, options...>::value <= 1,
+            "Invalid class_ base types: multiple inheritance is not supported");
+
     PYBIND11_OBJECT(class_, detail::generic_type, PyType_Check)
 
     template <typename... Extra>
@@ -843,6 +856,8 @@
         record.init_holder = init_holder;
         record.dealloc = dealloc;
 
+        detail::class_selector<is_base_class, options...>::set_bases(record);
+
         /* Process optional arguments, if any */
         detail::process_attributes<Extra...>::init(extra..., &record);
 
diff --git a/tests/test_inheritance.cpp b/tests/test_inheritance.cpp
index e1aad99..798beff 100644
--- a/tests/test_inheritance.cpp
+++ b/tests/test_inheritance.cpp
@@ -31,6 +31,11 @@
     Rabbit(const std::string &name) : Pet(name, "parrot") {}
 };
 
+class Hamster : public Pet {
+public:
+    Hamster(const std::string &name) : Pet(name, "rodent") {}
+};
+
 std::string pet_name_species(const Pet &pet) {
     return pet.name() + " is a " + pet.species();
 }
@@ -59,6 +64,10 @@
     py::class_<Rabbit>(m, "Rabbit", py::base<Pet>())
         .def(py::init<std::string>());
 
+    /* And another: list parent in class template arguments */
+    py::class_<Hamster, Pet>(m, "Hamster")
+        .def(py::init<std::string>());
+
     m.def("pet_name_species", pet_name_species);
     m.def("dog_bark", dog_bark);
 
diff --git a/tests/test_inheritance.py b/tests/test_inheritance.py
index b55490c..d4cea82 100644
--- a/tests/test_inheritance.py
+++ b/tests/test_inheritance.py
@@ -2,7 +2,7 @@
 
 
 def test_inheritance(msg):
-    from pybind11_tests import Pet, Dog, Rabbit, dog_bark, pet_name_species
+    from pybind11_tests import Pet, Dog, Rabbit, Hamster, dog_bark, pet_name_species
 
     roger = Rabbit('Rabbit')
     assert roger.name() + " is a " + roger.species() == "Rabbit is a parrot"
@@ -16,6 +16,9 @@
     assert molly.name() + " is a " + molly.species() == "Molly is a dog"
     assert pet_name_species(molly) == "Molly is a dog"
 
+    fred = Hamster('Fred')
+    assert fred.name() + " is a " + fred.species() == "Fred is a rodent"
+
     assert dog_bark(molly) == "Woof!"
 
     with pytest.raises(TypeError) as excinfo:
diff --git a/tests/test_issues.cpp b/tests/test_issues.cpp
index 0a5a0b0..55502fe 100644
--- a/tests/test_issues.cpp
+++ b/tests/test_issues.cpp
@@ -96,7 +96,7 @@
 
     py::class_<ElementBase, std::shared_ptr<ElementBase>> (m2, "ElementBase");
 
-    py::class_<ElementA, std::shared_ptr<ElementA>>(m2, "ElementA", py::base<ElementBase>())
+    py::class_<ElementA, ElementBase, std::shared_ptr<ElementA>>(m2, "ElementA")
         .def(py::init<int>())
         .def("value", &ElementA::value);
 
diff --git a/tests/test_virtual_functions.cpp b/tests/test_virtual_functions.cpp
index ac5b3fb..381b87e 100644
--- a/tests/test_virtual_functions.cpp
+++ b/tests/test_virtual_functions.cpp
@@ -258,12 +258,12 @@
         .def("unlucky_number", &A_Repeat::unlucky_number)
         .def("say_something", &A_Repeat::say_something)
         .def("say_everything", &A_Repeat::say_everything);
-    py::class_<B_Repeat, PyB_Repeat>(m, "B_Repeat", py::base<A_Repeat>())
+    py::class_<B_Repeat, A_Repeat, PyB_Repeat>(m, "B_Repeat")
         .def(py::init<>())
         .def("lucky_number", &B_Repeat::lucky_number);
-    py::class_<C_Repeat, PyC_Repeat>(m, "C_Repeat", py::base<B_Repeat>())
+    py::class_<C_Repeat, B_Repeat, PyC_Repeat>(m, "C_Repeat")
         .def(py::init<>());
-    py::class_<D_Repeat, PyD_Repeat>(m, "D_Repeat", py::base<C_Repeat>())
+    py::class_<D_Repeat, C_Repeat, PyD_Repeat>(m, "D_Repeat")
         .def(py::init<>());
 
     // Method 2: Templated trampolines
@@ -272,12 +272,12 @@
         .def("unlucky_number", &A_Tpl::unlucky_number)
         .def("say_something", &A_Tpl::say_something)
         .def("say_everything", &A_Tpl::say_everything);
-    py::class_<B_Tpl, PyB_Tpl<>>(m, "B_Tpl", py::base<A_Tpl>())
+    py::class_<B_Tpl, A_Tpl, PyB_Tpl<>>(m, "B_Tpl")
         .def(py::init<>())
         .def("lucky_number", &B_Tpl::lucky_number);
-    py::class_<C_Tpl, PyB_Tpl<C_Tpl>>(m, "C_Tpl", py::base<B_Tpl>())
+    py::class_<C_Tpl, B_Tpl, PyB_Tpl<C_Tpl>>(m, "C_Tpl")
         .def(py::init<>());
-    py::class_<D_Tpl, PyB_Tpl<D_Tpl>>(m, "D_Tpl", py::base<C_Tpl>())
+    py::class_<D_Tpl, C_Tpl, PyB_Tpl<D_Tpl>>(m, "D_Tpl")
         .def(py::init<>());
 
 };