Skip to content

Commit 2bc946b

Browse files
author
Wenzel Jakob
committed
copy/move constructor detection workaround (MSVC 2015 bug)
1 parent 8e93df8 commit 2bc946b

File tree

2 files changed

+23
-23
lines changed

2 files changed

+23
-23
lines changed

include/pybind11/cast.h

Lines changed: 23 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -225,6 +225,7 @@ using cast_op_type = typename std::conditional<std::is_pointer<typename std::rem
225225
typename std::add_pointer<typename intrinsic_type<T>::type>::type,
226226
typename std::add_lvalue_reference<typename intrinsic_type<T>::type>::type>::type;
227227

228+
228229
/// Generic type caster for objects stored on the heap
229230
template <typename type> class type_caster_base : public type_caster_generic {
230231
public:
@@ -247,22 +248,35 @@ template <typename type> class type_caster_base : public type_caster_generic {
247248
static handle cast(const type *src, return_value_policy policy, handle parent) {
248249
return type_caster_generic::cast(
249250
src, policy, parent, src ? &typeid(*src) : nullptr, &typeid(type),
250-
&copy_constructor, &move_constructor);
251+
make_copy_constructor(src), make_move_constructor(src));
251252
}
252253

253254
template <typename T> using cast_op_type = pybind11::detail::cast_op_type<T>;
254255

255256
operator type*() { return (type *) value; }
256257
operator type&() { return *((type *) value); }
258+
257259
protected:
258-
template <typename T = type, typename std::enable_if<detail::is_copy_constructible<T>::value, int>::type = 0>
259-
static void *copy_constructor(const void *arg) { return (void *) new type(*((const type *) arg)); }
260-
template <typename T = type, typename std::enable_if<!detail::is_copy_constructible<T>::value, int>::type = 0>
261-
static void *copy_constructor(const void *) { return nullptr; }
262-
template <typename T = type, typename std::enable_if<detail::is_move_constructible<T>::value, int>::type = 0>
263-
static void *move_constructor(const void *arg) { return (void *) new type(std::move(*((type *) arg))); }
264-
template <typename T = type, typename std::enable_if<!detail::is_move_constructible<T>::value, int>::type = 0>
265-
static void *move_constructor(const void *) { return nullptr; }
260+
typedef void *(*Constructor)(const void *stream);
261+
#if !defined(_MSC_VER)
262+
/* Only enabled when the types are {copy,move}-constructible *and* when the type
263+
does not have a private operator new implementaton. */
264+
template <typename T = type> static auto make_copy_constructor(const T *value) -> decltype(new T(*value), Constructor(nullptr)) {
265+
return [](const void *arg) -> void * { return new T(*((const T *) arg)); }; }
266+
template <typename T = type> static auto make_move_constructor(const T *value) -> decltype(new T(std::move(*((T *) value))), Constructor(nullptr)) {
267+
return [](const void *arg) -> void * { return (void *) new T(std::move(*((T *) arg))); }; }
268+
#else
269+
/* Visual Studio 2015's SFINAE implementation doesn't yet handle the above robustly in all situations.
270+
Use a workaround that only tests for constructibility for now. */
271+
template <typename T = type, typename = typename std::enable_if<std::is_copy_constructible<T>::value>::type>
272+
static Constructor make_copy_constructor(const T *value) {
273+
return [](const void *arg) -> void * { return new T(*((const T *)arg)); }; }
274+
template <typename T = type, typename = typename std::enable_if<std::is_move_constructible<T>::value>::type>
275+
static Constructor make_move_constructor(const T *value) {
276+
return [](const void *arg) -> void * { return (void *) new T(std::move(*((T *)arg))); }; }
277+
#endif
278+
static Constructor make_copy_constructor(...) { return nullptr; }
279+
static Constructor make_move_constructor(...) { return nullptr; }
266280
};
267281

268282
template <typename type, typename SFINAE = void> class type_caster : public type_caster_base<type> { };

include/pybind11/common.h

Lines changed: 0 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -293,20 +293,6 @@ template <typename T> struct intrinsic_type<T&&> { typedef type
293293
template <typename T, size_t N> struct intrinsic_type<const T[N]> { typedef typename intrinsic_type<T>::type type; };
294294
template <typename T, size_t N> struct intrinsic_type<T[N]> { typedef typename intrinsic_type<T>::type type; };
295295

296-
/** \brief SFINAE helper class to check if a copy constructor is usable (in contrast to
297-
* std::is_copy_constructible, this class also checks if the 'new' operator is accessible */
298-
template <typename T> struct is_copy_constructible {
299-
template <typename T2> static std::true_type test(decltype(new T2(std::declval<typename std::add_lvalue_reference<T2>::type>())) *);
300-
template <typename T2> static std::false_type test(...);
301-
static const bool value = std::is_same<std::true_type, decltype(test<T>(nullptr))>::value;
302-
};
303-
304-
template <typename T> struct is_move_constructible {
305-
template <typename T2> static std::true_type test(decltype(new T2(std::declval<T2>())) *);
306-
template <typename T2> static std::false_type test(...);
307-
static const bool value = std::is_same<std::true_type, decltype(test<T>(nullptr))>::value;
308-
};
309-
310296
/// Helper type to replace 'void' in some expressions
311297
struct void_type { };
312298

0 commit comments

Comments
 (0)