@@ -329,6 +329,18 @@ using cast_op_type = typename std::conditional<std::is_pointer<typename std::rem
329
329
typename std::add_pointer<intrinsic_t <T>>::type,
330
330
typename std::add_lvalue_reference<intrinsic_t <T>>::type>::type;
331
331
332
+ // std::is_copy_constructible isn't quite enough: it lets std::vector<T> (and similar) through when
333
+ // T is non-copyable, but code containing such a copy constructor fails to actually compile.
334
+ template <typename T, typename SFINAE = void > struct is_copy_constructible : std::is_copy_constructible<T> {};
335
+
336
+ // Specialization for types that appear to be copy constructible but also look like stl containers
337
+ // (we specifically check for: has `value_type` and `reference` with `reference = value_type&`): if
338
+ // so, copy constructability depends on whether the value_type is copy constructible.
339
+ template <typename Container> struct is_copy_constructible <Container, enable_if_t <
340
+ std::is_copy_constructible<Container>::value &&
341
+ std::is_same<typename Container::value_type &, typename Container::reference>::value
342
+ >> : std::is_copy_constructible<typename Container::value_type> {};
343
+
332
344
// / Generic type caster for objects stored on the heap
333
345
template <typename type> class type_caster_base : public type_caster_generic {
334
346
using itype = intrinsic_t <type>;
@@ -366,20 +378,21 @@ template <typename type> class type_caster_base : public type_caster_generic {
366
378
#if !defined(_MSC_VER)
367
379
/* Only enabled when the types are {copy,move}-constructible *and* when the type
368
380
does not have a private operator new implementaton. */
369
- template <typename T = type> static auto make_copy_constructor (const T *value) -> decltype(new T(*value), Constructor(nullptr )) {
381
+ template <typename T = type, typename = enable_if_t <is_copy_constructible<T>::value> > static auto make_copy_constructor (const T *value) -> decltype(new T(*value), Constructor(nullptr )) {
370
382
return [](const void *arg) -> void * { return new T (*((const T *) arg)); }; }
371
383
template <typename T = type> static auto make_move_constructor (const T *value) -> decltype(new T(std::move(*((T *) value))), Constructor(nullptr )) {
372
384
return [](const void *arg) -> void * { return (void *) new T (std::move (*((T *) arg))); }; }
373
385
#else
374
386
/* Visual Studio 2015's SFINAE implementation doesn't yet handle the above robustly in all situations.
375
387
Use a workaround that only tests for constructibility for now. */
376
- template <typename T = type, typename = enable_if_t <std:: is_copy_constructible<T>::value>>
388
+ template <typename T = type, typename = enable_if_t <is_copy_constructible<T>::value>>
377
389
static Constructor make_copy_constructor (const T *value) {
378
390
return [](const void *arg) -> void * { return new T (*((const T *)arg)); }; }
379
391
template <typename T = type, typename = enable_if_t <std::is_move_constructible<T>::value>>
380
392
static Constructor make_move_constructor (const T *value) {
381
393
return [](const void *arg) -> void * { return (void *) new T (std::move (*((T *)arg))); }; }
382
394
#endif
395
+
383
396
static Constructor make_copy_constructor (...) { return nullptr ; }
384
397
static Constructor make_move_constructor (...) { return nullptr ; }
385
398
};
0 commit comments