mirror of
https://github.com/pybind/pybind11.git
synced 2024-11-11 08:03:55 +00:00
Enable detection of private operator new on MSVC
MSVC 2015 Update 3 and 2017 can handle enough expression SFINAE to make this work now.
This commit is contained in:
parent
6223b18cea
commit
e27ea47c87
@ -492,23 +492,12 @@ public:
|
||||
|
||||
protected:
|
||||
typedef void *(*Constructor)(const void *stream);
|
||||
#if !defined(_MSC_VER)
|
||||
/* Only enabled when the types are {copy,move}-constructible *and* when the type
|
||||
does not have a private operator new implementaton. */
|
||||
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)) {
|
||||
return [](const void *arg) -> void * { return new T(*((const T *) arg)); }; }
|
||||
template <typename T = type> static auto make_move_constructor(const T *value) -> decltype(new T(std::move(*((T *) value))), Constructor(nullptr)) {
|
||||
return [](const void *arg) -> void * { return (void *) new T(std::move(*const_cast<T *>(reinterpret_cast<const T *>(arg)))); }; }
|
||||
#else
|
||||
/* Visual Studio 2015's SFINAE implementation doesn't yet handle the above robustly in all situations.
|
||||
Use a workaround that only tests for constructibility for now. */
|
||||
template <typename T = type, typename = enable_if_t<is_copy_constructible<T>::value>>
|
||||
static Constructor make_copy_constructor(const T *value) {
|
||||
return [](const void *arg) -> void * { return new T(*((const T *)arg)); }; }
|
||||
template <typename T = type, typename = enable_if_t<std::is_move_constructible<T>::value>>
|
||||
static Constructor make_move_constructor(const T *value) {
|
||||
return [](const void *arg) -> void * { return (void *) new T(std::move(*((T *)arg))); }; }
|
||||
#endif
|
||||
|
||||
static Constructor make_copy_constructor(...) { return nullptr; }
|
||||
static Constructor make_move_constructor(...) { return nullptr; }
|
||||
|
@ -98,6 +98,12 @@ public:
|
||||
};
|
||||
}}
|
||||
|
||||
struct PrivateOpNew {
|
||||
int value = 1;
|
||||
|
||||
private:
|
||||
void *operator new(size_t bytes);
|
||||
};
|
||||
|
||||
test_initializer copy_move_policies([](py::module &m) {
|
||||
py::class_<lacking_copy_ctor>(m, "lacking_copy_ctor")
|
||||
@ -174,4 +180,11 @@ test_initializer copy_move_policies([](py::module &m) {
|
||||
m.attr("has_optional") = false;
|
||||
#endif
|
||||
|
||||
// #70 compilation issue if operator new is not public
|
||||
py::class_<PrivateOpNew>(m, "PrivateOpNew").def_readonly("value", &PrivateOpNew::value);
|
||||
m.def("private_op_new_value", []() { return PrivateOpNew(); });
|
||||
m.def("private_op_new_reference", []() -> const PrivateOpNew & {
|
||||
static PrivateOpNew x{};
|
||||
return x;
|
||||
}, py::return_value_policy::reference);
|
||||
});
|
||||
|
@ -98,3 +98,14 @@ def test_move_and_copy_load_optional():
|
||||
assert c_c.copy_assignments == 2
|
||||
assert c_c.copy_constructions == 5
|
||||
assert c_m.alive() + c_mc.alive() + c_c.alive() == 0
|
||||
|
||||
|
||||
def test_private_op_new():
|
||||
"""An object with a private `operator new` cannot be returned by value"""
|
||||
import pybind11_tests as m
|
||||
|
||||
with pytest.raises(RuntimeError) as excinfo:
|
||||
m.private_op_new_value()
|
||||
assert "the object is neither movable nor copyable" in str(excinfo.value)
|
||||
|
||||
assert m.private_op_new_reference().value == 1
|
||||
|
@ -77,16 +77,6 @@ template <> struct hash<TplConstrClass> { size_t operator()(const TplConstrClass
|
||||
void init_issues(py::module &m) {
|
||||
py::module m2 = m.def_submodule("issues");
|
||||
|
||||
#if !defined(_MSC_VER)
|
||||
// Visual Studio 2015 currently cannot compile this test
|
||||
// (see the comment in type_caster_base::make_copy_constructor)
|
||||
// #70 compilation issue if operator new is not public
|
||||
class NonConstructible { private: void *operator new(size_t bytes) throw(); };
|
||||
py::class_<NonConstructible>(m, "Foo");
|
||||
m2.def("getstmt", []() -> NonConstructible * { return nullptr; },
|
||||
py::return_value_policy::reference);
|
||||
#endif
|
||||
|
||||
// #137: const char* isn't handled properly
|
||||
m2.def("print_cchar", [](const char *s) { return std::string(s); });
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user