Fixed stl casters to use the appropriate type_caster cast_op_type (#529)

stl casters were using a value cast to (Value) or (Key), but that isn't
always appropriate.  This changes it to use the appropriate value
converter's cast_op_type.
diff --git a/include/pybind11/stl.h b/include/pybind11/stl.h
index c1ed0f9..f806a11 100644
--- a/include/pybind11/stl.h
+++ b/include/pybind11/stl.h
@@ -53,7 +53,7 @@
         for (auto entry : s) {
             if (!conv.load(entry, convert))
                 return false;
-            value.insert((Key) conv);
+            value.insert(conv.operator typename key_conv::template cast_op_type<Key>());
         }
         return true;
     }
@@ -87,7 +87,9 @@
             if (!kconv.load(it.first.ptr(), convert) ||
                 !vconv.load(it.second.ptr(), convert))
                 return false;
-            value.emplace((Key) kconv, (Value) vconv);
+            value.emplace(
+                    kconv.operator typename   key_conv::template cast_op_type<Key>(),
+                    vconv.operator typename value_conv::template cast_op_type<Value>());
         }
         return true;
     }
@@ -121,7 +123,7 @@
         for (auto it : s) {
             if (!conv.load(it, convert))
                 return false;
-            value.push_back((Value) conv);
+            value.push_back(conv.operator typename value_conv::template cast_op_type<Value>());
         }
         return true;
     }
@@ -167,7 +169,7 @@
         for (auto it : l) {
             if (!conv.load(it, convert))
                 return false;
-            value[ctr++] = (Type) conv;
+            value[ctr++] = conv.operator typename value_conv::template cast_op_type<Type>();
         }
         return true;
     }
@@ -200,13 +202,12 @@
 
 // This type caster is intended to be used for std::optional and std::experimental::optional
 template<typename T> struct optional_caster {
-    using value_type = typename intrinsic_type<typename T::value_type>::type;
-    using caster_type = type_caster<value_type>;
+    using value_conv = make_caster<typename T::value_type>;
 
     static handle cast(const T& src, return_value_policy policy, handle parent) {
         if (!src)
             return none().inc_ref();
-        return caster_type::cast(*src, policy, parent);
+        return value_conv::cast(*src, policy, parent);
     }
 
     bool load(handle src, bool convert) {
@@ -215,18 +216,16 @@
         } else if (src.is_none()) {
             value = {};  // nullopt
             return true;
-        } else if (!inner.load(src, convert)) {
-            return false;
-        } else {
-            value.emplace(static_cast<const value_type&>(inner));
-            return true;
         }
+        value_conv inner_caster;
+        if (!inner_caster.load(src, convert))
+            return false;
+
+        value.emplace(inner_caster.operator typename value_conv::template cast_op_type<typename T::value_type>());
+        return true;
     }
 
-    PYBIND11_TYPE_CASTER(T, _("Optional[") + caster_type::name() + _("]"));
-
-private:
-    caster_type inner;
+    PYBIND11_TYPE_CASTER(T, _("Optional[") + value_conv::name() + _("]"));
 };
 
 #if PYBIND11_HAS_OPTIONAL
diff --git a/tests/test_issues.cpp b/tests/test_issues.cpp
index 33f8a43..378da52 100644
--- a/tests/test_issues.cpp
+++ b/tests/test_issues.cpp
@@ -64,6 +64,15 @@
 };
 PYBIND11_DECLARE_HOLDER_TYPE(T, custom_unique_ptr<T>);
 
+/// Issue #528: templated constructor
+struct TplConstrClass {
+    template <typename T> TplConstrClass(const T &arg) : str{arg} {}
+    std::string str;
+    bool operator==(const TplConstrClass &t) const { return t.str == str; }
+};
+namespace std {
+template <> struct hash<TplConstrClass> { size_t operator()(const TplConstrClass &t) const { return std::hash<std::string>()(t.str); } };
+}
 
 
 void init_issues(py::module &m) {
@@ -371,6 +380,16 @@
     py::class_<MyDerived, MyBase>(m2, "MyDerived")
         .def_static("make", &MyDerived::make)
         .def_static("make2", &MyDerived::make);
+
+    /// Issue #528: templated constructor
+    m2.def("tpl_constr_vector", [](std::vector<TplConstrClass> &) {});
+    m2.def("tpl_constr_map", [](std::unordered_map<TplConstrClass, TplConstrClass> &) {});
+    m2.def("tpl_constr_set", [](std::unordered_set<TplConstrClass> &) {});
+#if defined(PYBIND11_HAS_OPTIONAL)
+    m2.def("tpl_constr_optional", [](std::optional<TplConstrClass> &) {});
+#elif defined(PYBIND11_HAS_EXP_OPTIONAL)
+    m2.def("tpl_constr_optional", [](std::experimental::optional<TplConstrClass> &) {});
+#endif
 }
 
 // MSVC workaround: trying to use a lambda here crashes MSCV