Skip to content

Commit 1f13b0c

Browse files
committed
Workaround for py::dict() constructor on MSVC
MSVC fails to compile if the constructor is defined out-of-line. The error states that it cannot deduce the type of the default template parameter which is used for SFINAE.
1 parent 08eb4ff commit 1f13b0c

File tree

3 files changed

+18
-9
lines changed

3 files changed

+18
-9
lines changed

include/pybind11/cast.h

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -970,7 +970,7 @@ template <template<typename> class Predicate, typename... Ts>
970970
constexpr int constexpr_last() { return constexpr_impl::last(0, -1, Predicate<Ts>::value...); }
971971

972972
/// Collect only positional arguments
973-
template <return_value_policy policy = return_value_policy::automatic_reference>
973+
template <return_value_policy policy>
974974
class simple_collector {
975975
public:
976976
template <typename... Ts>
@@ -995,7 +995,7 @@ class simple_collector {
995995
};
996996

997997
/// Collect positional, keyword, * and ** arguments
998-
template <return_value_policy policy = return_value_policy::automatic_reference>
998+
template <return_value_policy policy>
999999
class unpacking_collector {
10001000
public:
10011001
template <typename... Ts>
@@ -1133,10 +1133,6 @@ template <return_value_policy policy,
11331133
return operator()<policy>(std::forward<Args>(args)...);
11341134
}
11351135

1136-
template <typename... Args, typename /*SFINAE*/>
1137-
dict::dict(Args &&...args)
1138-
: dict(detail::unpacking_collector<>(std::forward<Args>(args)...).kwargs()) { }
1139-
11401136
#define PYBIND11_MAKE_OPAQUE(Type) \
11411137
namespace pybind11 { namespace detail { \
11421138
template<> class type_caster<Type> : public type_caster_base<Type> { }; \

include/pybind11/common.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -242,7 +242,7 @@ struct buffer_info {
242242
(*this) = std::move(other);
243243
}
244244

245-
buffer_info& operator=(buffer_info &&rhs){
245+
buffer_info& operator=(buffer_info &&rhs) {
246246
ptr = rhs.ptr;
247247
itemsize = rhs.itemsize;
248248
size = rhs.size;
@@ -349,6 +349,10 @@ template <template<typename> class Predicate, typename... Ts>
349349
using any_of_t = negation<std::is_same<bools<Predicate<Ts>::value...>,
350350
bools<always_false<Ts>::value...>>>;
351351

352+
/// Defer the evaluation of type T until types Us are instantiated
353+
template <typename T, typename... /*Us*/> struct deferred_type { using type = T; };
354+
template <typename T, typename... Us> using deferred_t = typename deferred_type<T, Us...>::type;
355+
352356
/// Ignore that a variable is unused in compiler warnings
353357
inline void ignore_unused(const int *) { }
354358

include/pybind11/pytypes.h

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -259,6 +259,12 @@ template <typename T> using is_keyword_or_ds = bool_constant<
259259
is_keyword<T>::value || is_ds_unpacking<T>::value
260260
>;
261261

262+
// Call argument collector forward declarations
263+
template <return_value_policy policy = return_value_policy::automatic_reference>
264+
class simple_collector;
265+
template <return_value_policy policy = return_value_policy::automatic_reference>
266+
class unpacking_collector;
267+
262268
NAMESPACE_END(detail)
263269

264270
#define PYBIND11_OBJECT_CVT(Name, Parent, CheckFun, CvtStmt) \
@@ -588,8 +594,11 @@ class dict : public object {
588594
if (!m_ptr) pybind11_fail("Could not allocate dict object!");
589595
}
590596
template <typename... Args,
591-
typename = detail::enable_if_t<detail::all_of_t<detail::is_keyword_or_ds, Args...>::value>>
592-
dict(Args &&...args);
597+
typename = detail::enable_if_t<detail::all_of_t<detail::is_keyword_or_ds, Args...>::value>,
598+
// MSVC workaround: it can't compile an out-of-line definition, so defer the collector
599+
typename collector = detail::deferred_t<detail::unpacking_collector<>, Args...>>
600+
dict(Args &&...args) : dict(collector(std::forward<Args>(args)...).kwargs()) { }
601+
593602
size_t size() const { return (size_t) PyDict_Size(m_ptr); }
594603
detail::dict_iterator begin() const { return (++detail::dict_iterator(*this, 0)); }
595604
detail::dict_iterator end() const { return detail::dict_iterator(); }

0 commit comments

Comments
 (0)