112391Sjason@lowepower.com/* 212391Sjason@lowepower.com tests/test_class.cpp -- test py::class_ definitions and basic functionality 312391Sjason@lowepower.com 412391Sjason@lowepower.com Copyright (c) 2016 Wenzel Jakob <wenzel.jakob@epfl.ch> 512391Sjason@lowepower.com 612391Sjason@lowepower.com All rights reserved. Use of this source code is governed by a 712391Sjason@lowepower.com BSD-style license that can be found in the LICENSE file. 812391Sjason@lowepower.com*/ 912391Sjason@lowepower.com 1012391Sjason@lowepower.com#include "pybind11_tests.h" 1112391Sjason@lowepower.com#include "constructor_stats.h" 1212391Sjason@lowepower.com#include "local_bindings.h" 1314299Sbbruce@ucdavis.edu#include <pybind11/stl.h> 1414299Sbbruce@ucdavis.edu 1514299Sbbruce@ucdavis.edu#if defined(_MSC_VER) 1614299Sbbruce@ucdavis.edu# pragma warning(disable: 4324) // warning C4324: structure was padded due to alignment specifier 1714299Sbbruce@ucdavis.edu#endif 1814299Sbbruce@ucdavis.edu 1914299Sbbruce@ucdavis.edu// test_brace_initialization 2014299Sbbruce@ucdavis.edustruct NoBraceInitialization { 2114299Sbbruce@ucdavis.edu NoBraceInitialization(std::vector<int> v) : vec{std::move(v)} {} 2214299Sbbruce@ucdavis.edu template <typename T> 2314299Sbbruce@ucdavis.edu NoBraceInitialization(std::initializer_list<T> l) : vec(l) {} 2414299Sbbruce@ucdavis.edu 2514299Sbbruce@ucdavis.edu std::vector<int> vec; 2614299Sbbruce@ucdavis.edu}; 2712391Sjason@lowepower.com 2812391Sjason@lowepower.comTEST_SUBMODULE(class_, m) { 2912391Sjason@lowepower.com // test_instance 3012391Sjason@lowepower.com struct NoConstructor { 3114299Sbbruce@ucdavis.edu NoConstructor() = default; 3214299Sbbruce@ucdavis.edu NoConstructor(const NoConstructor &) = default; 3314299Sbbruce@ucdavis.edu NoConstructor(NoConstructor &&) = default; 3412391Sjason@lowepower.com static NoConstructor *new_instance() { 3512391Sjason@lowepower.com auto *ptr = new NoConstructor(); 3612391Sjason@lowepower.com print_created(ptr, "via new_instance"); 3712391Sjason@lowepower.com return ptr; 3812391Sjason@lowepower.com } 3912391Sjason@lowepower.com ~NoConstructor() { print_destroyed(this); } 4012391Sjason@lowepower.com }; 4112391Sjason@lowepower.com 4212391Sjason@lowepower.com py::class_<NoConstructor>(m, "NoConstructor") 4312391Sjason@lowepower.com .def_static("new_instance", &NoConstructor::new_instance, "Return an instance"); 4412391Sjason@lowepower.com 4512391Sjason@lowepower.com // test_inheritance 4612391Sjason@lowepower.com class Pet { 4712391Sjason@lowepower.com public: 4812391Sjason@lowepower.com Pet(const std::string &name, const std::string &species) 4912391Sjason@lowepower.com : m_name(name), m_species(species) {} 5012391Sjason@lowepower.com std::string name() const { return m_name; } 5112391Sjason@lowepower.com std::string species() const { return m_species; } 5212391Sjason@lowepower.com private: 5312391Sjason@lowepower.com std::string m_name; 5412391Sjason@lowepower.com std::string m_species; 5512391Sjason@lowepower.com }; 5612391Sjason@lowepower.com 5712391Sjason@lowepower.com class Dog : public Pet { 5812391Sjason@lowepower.com public: 5912391Sjason@lowepower.com Dog(const std::string &name) : Pet(name, "dog") {} 6012391Sjason@lowepower.com std::string bark() const { return "Woof!"; } 6112391Sjason@lowepower.com }; 6212391Sjason@lowepower.com 6312391Sjason@lowepower.com class Rabbit : public Pet { 6412391Sjason@lowepower.com public: 6512391Sjason@lowepower.com Rabbit(const std::string &name) : Pet(name, "parrot") {} 6612391Sjason@lowepower.com }; 6712391Sjason@lowepower.com 6812391Sjason@lowepower.com class Hamster : public Pet { 6912391Sjason@lowepower.com public: 7012391Sjason@lowepower.com Hamster(const std::string &name) : Pet(name, "rodent") {} 7112391Sjason@lowepower.com }; 7212391Sjason@lowepower.com 7312391Sjason@lowepower.com class Chimera : public Pet { 7412391Sjason@lowepower.com Chimera() : Pet("Kimmy", "chimera") {} 7512391Sjason@lowepower.com }; 7612391Sjason@lowepower.com 7712391Sjason@lowepower.com py::class_<Pet> pet_class(m, "Pet"); 7812391Sjason@lowepower.com pet_class 7912391Sjason@lowepower.com .def(py::init<std::string, std::string>()) 8012391Sjason@lowepower.com .def("name", &Pet::name) 8112391Sjason@lowepower.com .def("species", &Pet::species); 8212391Sjason@lowepower.com 8312391Sjason@lowepower.com /* One way of declaring a subclass relationship: reference parent's class_ object */ 8412391Sjason@lowepower.com py::class_<Dog>(m, "Dog", pet_class) 8512391Sjason@lowepower.com .def(py::init<std::string>()); 8612391Sjason@lowepower.com 8712391Sjason@lowepower.com /* Another way of declaring a subclass relationship: reference parent's C++ type */ 8812391Sjason@lowepower.com py::class_<Rabbit, Pet>(m, "Rabbit") 8912391Sjason@lowepower.com .def(py::init<std::string>()); 9012391Sjason@lowepower.com 9112391Sjason@lowepower.com /* And another: list parent in class template arguments */ 9212391Sjason@lowepower.com py::class_<Hamster, Pet>(m, "Hamster") 9312391Sjason@lowepower.com .def(py::init<std::string>()); 9412391Sjason@lowepower.com 9512391Sjason@lowepower.com /* Constructors are not inherited by default */ 9612391Sjason@lowepower.com py::class_<Chimera, Pet>(m, "Chimera"); 9712391Sjason@lowepower.com 9812391Sjason@lowepower.com m.def("pet_name_species", [](const Pet &pet) { return pet.name() + " is a " + pet.species(); }); 9912391Sjason@lowepower.com m.def("dog_bark", [](const Dog &dog) { return dog.bark(); }); 10012391Sjason@lowepower.com 10112391Sjason@lowepower.com // test_automatic_upcasting 10214299Sbbruce@ucdavis.edu struct BaseClass { 10314299Sbbruce@ucdavis.edu BaseClass() = default; 10414299Sbbruce@ucdavis.edu BaseClass(const BaseClass &) = default; 10514299Sbbruce@ucdavis.edu BaseClass(BaseClass &&) = default; 10614299Sbbruce@ucdavis.edu virtual ~BaseClass() {} 10714299Sbbruce@ucdavis.edu }; 10812391Sjason@lowepower.com struct DerivedClass1 : BaseClass { }; 10912391Sjason@lowepower.com struct DerivedClass2 : BaseClass { }; 11012391Sjason@lowepower.com 11112391Sjason@lowepower.com py::class_<BaseClass>(m, "BaseClass").def(py::init<>()); 11212391Sjason@lowepower.com py::class_<DerivedClass1>(m, "DerivedClass1").def(py::init<>()); 11312391Sjason@lowepower.com py::class_<DerivedClass2>(m, "DerivedClass2").def(py::init<>()); 11412391Sjason@lowepower.com 11512391Sjason@lowepower.com m.def("return_class_1", []() -> BaseClass* { return new DerivedClass1(); }); 11612391Sjason@lowepower.com m.def("return_class_2", []() -> BaseClass* { return new DerivedClass2(); }); 11712391Sjason@lowepower.com m.def("return_class_n", [](int n) -> BaseClass* { 11812391Sjason@lowepower.com if (n == 1) return new DerivedClass1(); 11912391Sjason@lowepower.com if (n == 2) return new DerivedClass2(); 12012391Sjason@lowepower.com return new BaseClass(); 12112391Sjason@lowepower.com }); 12212391Sjason@lowepower.com m.def("return_none", []() -> BaseClass* { return nullptr; }); 12312391Sjason@lowepower.com 12412391Sjason@lowepower.com // test_isinstance 12512391Sjason@lowepower.com m.def("check_instances", [](py::list l) { 12612391Sjason@lowepower.com return py::make_tuple( 12712391Sjason@lowepower.com py::isinstance<py::tuple>(l[0]), 12812391Sjason@lowepower.com py::isinstance<py::dict>(l[1]), 12912391Sjason@lowepower.com py::isinstance<Pet>(l[2]), 13012391Sjason@lowepower.com py::isinstance<Pet>(l[3]), 13112391Sjason@lowepower.com py::isinstance<Dog>(l[4]), 13212391Sjason@lowepower.com py::isinstance<Rabbit>(l[5]), 13312391Sjason@lowepower.com py::isinstance<UnregisteredType>(l[6]) 13412391Sjason@lowepower.com ); 13512391Sjason@lowepower.com }); 13612391Sjason@lowepower.com 13712391Sjason@lowepower.com // test_mismatched_holder 13812391Sjason@lowepower.com struct MismatchBase1 { }; 13912391Sjason@lowepower.com struct MismatchDerived1 : MismatchBase1 { }; 14012391Sjason@lowepower.com 14112391Sjason@lowepower.com struct MismatchBase2 { }; 14212391Sjason@lowepower.com struct MismatchDerived2 : MismatchBase2 { }; 14312391Sjason@lowepower.com 14412391Sjason@lowepower.com m.def("mismatched_holder_1", []() { 14512391Sjason@lowepower.com auto mod = py::module::import("__main__"); 14612391Sjason@lowepower.com py::class_<MismatchBase1, std::shared_ptr<MismatchBase1>>(mod, "MismatchBase1"); 14712391Sjason@lowepower.com py::class_<MismatchDerived1, MismatchBase1>(mod, "MismatchDerived1"); 14812391Sjason@lowepower.com }); 14912391Sjason@lowepower.com m.def("mismatched_holder_2", []() { 15012391Sjason@lowepower.com auto mod = py::module::import("__main__"); 15112391Sjason@lowepower.com py::class_<MismatchBase2>(mod, "MismatchBase2"); 15212391Sjason@lowepower.com py::class_<MismatchDerived2, std::shared_ptr<MismatchDerived2>, 15312391Sjason@lowepower.com MismatchBase2>(mod, "MismatchDerived2"); 15412391Sjason@lowepower.com }); 15512391Sjason@lowepower.com 15612391Sjason@lowepower.com // test_override_static 15712391Sjason@lowepower.com // #511: problem with inheritance + overwritten def_static 15812391Sjason@lowepower.com struct MyBase { 15912391Sjason@lowepower.com static std::unique_ptr<MyBase> make() { 16012391Sjason@lowepower.com return std::unique_ptr<MyBase>(new MyBase()); 16112391Sjason@lowepower.com } 16212391Sjason@lowepower.com }; 16312391Sjason@lowepower.com 16412391Sjason@lowepower.com struct MyDerived : MyBase { 16512391Sjason@lowepower.com static std::unique_ptr<MyDerived> make() { 16612391Sjason@lowepower.com return std::unique_ptr<MyDerived>(new MyDerived()); 16712391Sjason@lowepower.com } 16812391Sjason@lowepower.com }; 16912391Sjason@lowepower.com 17012391Sjason@lowepower.com py::class_<MyBase>(m, "MyBase") 17112391Sjason@lowepower.com .def_static("make", &MyBase::make); 17212391Sjason@lowepower.com 17312391Sjason@lowepower.com py::class_<MyDerived, MyBase>(m, "MyDerived") 17412391Sjason@lowepower.com .def_static("make", &MyDerived::make) 17512391Sjason@lowepower.com .def_static("make2", &MyDerived::make); 17612391Sjason@lowepower.com 17712391Sjason@lowepower.com // test_implicit_conversion_life_support 17812391Sjason@lowepower.com struct ConvertibleFromUserType { 17912391Sjason@lowepower.com int i; 18012391Sjason@lowepower.com 18112391Sjason@lowepower.com ConvertibleFromUserType(UserType u) : i(u.value()) { } 18212391Sjason@lowepower.com }; 18312391Sjason@lowepower.com 18412391Sjason@lowepower.com py::class_<ConvertibleFromUserType>(m, "AcceptsUserType") 18512391Sjason@lowepower.com .def(py::init<UserType>()); 18612391Sjason@lowepower.com py::implicitly_convertible<UserType, ConvertibleFromUserType>(); 18712391Sjason@lowepower.com 18812391Sjason@lowepower.com m.def("implicitly_convert_argument", [](const ConvertibleFromUserType &r) { return r.i; }); 18912391Sjason@lowepower.com m.def("implicitly_convert_variable", [](py::object o) { 19012391Sjason@lowepower.com // `o` is `UserType` and `r` is a reference to a temporary created by implicit 19112391Sjason@lowepower.com // conversion. This is valid when called inside a bound function because the temp 19212391Sjason@lowepower.com // object is attached to the same life support system as the arguments. 19312391Sjason@lowepower.com const auto &r = o.cast<const ConvertibleFromUserType &>(); 19412391Sjason@lowepower.com return r.i; 19512391Sjason@lowepower.com }); 19612391Sjason@lowepower.com m.add_object("implicitly_convert_variable_fail", [&] { 19712391Sjason@lowepower.com auto f = [](PyObject *, PyObject *args) -> PyObject * { 19812391Sjason@lowepower.com auto o = py::reinterpret_borrow<py::tuple>(args)[0]; 19912391Sjason@lowepower.com try { // It should fail here because there is no life support. 20012391Sjason@lowepower.com o.cast<const ConvertibleFromUserType &>(); 20112391Sjason@lowepower.com } catch (const py::cast_error &e) { 20212391Sjason@lowepower.com return py::str(e.what()).release().ptr(); 20312391Sjason@lowepower.com } 20412391Sjason@lowepower.com return py::str().release().ptr(); 20512391Sjason@lowepower.com }; 20612391Sjason@lowepower.com 20712391Sjason@lowepower.com auto def = new PyMethodDef{"f", f, METH_VARARGS, nullptr}; 20812391Sjason@lowepower.com return py::reinterpret_steal<py::object>(PyCFunction_NewEx(def, nullptr, m.ptr())); 20912391Sjason@lowepower.com }()); 21012391Sjason@lowepower.com 21112391Sjason@lowepower.com // test_operator_new_delete 21212391Sjason@lowepower.com struct HasOpNewDel { 21312391Sjason@lowepower.com std::uint64_t i; 21412391Sjason@lowepower.com static void *operator new(size_t s) { py::print("A new", s); return ::operator new(s); } 21512391Sjason@lowepower.com static void *operator new(size_t s, void *ptr) { py::print("A placement-new", s); return ptr; } 21612391Sjason@lowepower.com static void operator delete(void *p) { py::print("A delete"); return ::operator delete(p); } 21712391Sjason@lowepower.com }; 21812391Sjason@lowepower.com struct HasOpNewDelSize { 21912391Sjason@lowepower.com std::uint32_t i; 22012391Sjason@lowepower.com static void *operator new(size_t s) { py::print("B new", s); return ::operator new(s); } 22112391Sjason@lowepower.com static void *operator new(size_t s, void *ptr) { py::print("B placement-new", s); return ptr; } 22212391Sjason@lowepower.com static void operator delete(void *p, size_t s) { py::print("B delete", s); return ::operator delete(p); } 22312391Sjason@lowepower.com }; 22412391Sjason@lowepower.com struct AliasedHasOpNewDelSize { 22512391Sjason@lowepower.com std::uint64_t i; 22612391Sjason@lowepower.com static void *operator new(size_t s) { py::print("C new", s); return ::operator new(s); } 22712391Sjason@lowepower.com static void *operator new(size_t s, void *ptr) { py::print("C placement-new", s); return ptr; } 22812391Sjason@lowepower.com static void operator delete(void *p, size_t s) { py::print("C delete", s); return ::operator delete(p); } 22912391Sjason@lowepower.com virtual ~AliasedHasOpNewDelSize() = default; 23012391Sjason@lowepower.com }; 23112391Sjason@lowepower.com struct PyAliasedHasOpNewDelSize : AliasedHasOpNewDelSize { 23212391Sjason@lowepower.com PyAliasedHasOpNewDelSize() = default; 23312391Sjason@lowepower.com PyAliasedHasOpNewDelSize(int) { } 23412391Sjason@lowepower.com std::uint64_t j; 23512391Sjason@lowepower.com }; 23612391Sjason@lowepower.com struct HasOpNewDelBoth { 23712391Sjason@lowepower.com std::uint32_t i[8]; 23812391Sjason@lowepower.com static void *operator new(size_t s) { py::print("D new", s); return ::operator new(s); } 23912391Sjason@lowepower.com static void *operator new(size_t s, void *ptr) { py::print("D placement-new", s); return ptr; } 24012391Sjason@lowepower.com static void operator delete(void *p) { py::print("D delete"); return ::operator delete(p); } 24112391Sjason@lowepower.com static void operator delete(void *p, size_t s) { py::print("D wrong delete", s); return ::operator delete(p); } 24212391Sjason@lowepower.com }; 24312391Sjason@lowepower.com py::class_<HasOpNewDel>(m, "HasOpNewDel").def(py::init<>()); 24412391Sjason@lowepower.com py::class_<HasOpNewDelSize>(m, "HasOpNewDelSize").def(py::init<>()); 24512391Sjason@lowepower.com py::class_<HasOpNewDelBoth>(m, "HasOpNewDelBoth").def(py::init<>()); 24612391Sjason@lowepower.com py::class_<AliasedHasOpNewDelSize, PyAliasedHasOpNewDelSize> aliased(m, "AliasedHasOpNewDelSize"); 24712391Sjason@lowepower.com aliased.def(py::init<>()); 24812391Sjason@lowepower.com aliased.attr("size_noalias") = py::int_(sizeof(AliasedHasOpNewDelSize)); 24912391Sjason@lowepower.com aliased.attr("size_alias") = py::int_(sizeof(PyAliasedHasOpNewDelSize)); 25012391Sjason@lowepower.com 25112391Sjason@lowepower.com // This test is actually part of test_local_bindings (test_duplicate_local), but we need a 25212391Sjason@lowepower.com // definition in a different compilation unit within the same module: 25312391Sjason@lowepower.com bind_local<LocalExternal, 17>(m, "LocalExternal", py::module_local()); 25412391Sjason@lowepower.com 25512391Sjason@lowepower.com // test_bind_protected_functions 25612391Sjason@lowepower.com class ProtectedA { 25712391Sjason@lowepower.com protected: 25812391Sjason@lowepower.com int foo() const { return value; } 25912391Sjason@lowepower.com 26012391Sjason@lowepower.com private: 26112391Sjason@lowepower.com int value = 42; 26212391Sjason@lowepower.com }; 26312391Sjason@lowepower.com 26412391Sjason@lowepower.com class PublicistA : public ProtectedA { 26512391Sjason@lowepower.com public: 26612391Sjason@lowepower.com using ProtectedA::foo; 26712391Sjason@lowepower.com }; 26812391Sjason@lowepower.com 26912391Sjason@lowepower.com py::class_<ProtectedA>(m, "ProtectedA") 27012391Sjason@lowepower.com .def(py::init<>()) 27112391Sjason@lowepower.com#if !defined(_MSC_VER) || _MSC_VER >= 1910 27212391Sjason@lowepower.com .def("foo", &PublicistA::foo); 27312391Sjason@lowepower.com#else 27412391Sjason@lowepower.com .def("foo", static_cast<int (ProtectedA::*)() const>(&PublicistA::foo)); 27512391Sjason@lowepower.com#endif 27612391Sjason@lowepower.com 27712391Sjason@lowepower.com class ProtectedB { 27812391Sjason@lowepower.com public: 27912391Sjason@lowepower.com virtual ~ProtectedB() = default; 28012391Sjason@lowepower.com 28112391Sjason@lowepower.com protected: 28212391Sjason@lowepower.com virtual int foo() const { return value; } 28312391Sjason@lowepower.com 28412391Sjason@lowepower.com private: 28512391Sjason@lowepower.com int value = 42; 28612391Sjason@lowepower.com }; 28712391Sjason@lowepower.com 28812391Sjason@lowepower.com class TrampolineB : public ProtectedB { 28912391Sjason@lowepower.com public: 29012391Sjason@lowepower.com int foo() const override { PYBIND11_OVERLOAD(int, ProtectedB, foo, ); } 29112391Sjason@lowepower.com }; 29212391Sjason@lowepower.com 29312391Sjason@lowepower.com class PublicistB : public ProtectedB { 29412391Sjason@lowepower.com public: 29512391Sjason@lowepower.com using ProtectedB::foo; 29612391Sjason@lowepower.com }; 29712391Sjason@lowepower.com 29812391Sjason@lowepower.com py::class_<ProtectedB, TrampolineB>(m, "ProtectedB") 29912391Sjason@lowepower.com .def(py::init<>()) 30012391Sjason@lowepower.com#if !defined(_MSC_VER) || _MSC_VER >= 1910 30112391Sjason@lowepower.com .def("foo", &PublicistB::foo); 30212391Sjason@lowepower.com#else 30312391Sjason@lowepower.com .def("foo", static_cast<int (ProtectedB::*)() const>(&PublicistB::foo)); 30412391Sjason@lowepower.com#endif 30512391Sjason@lowepower.com 30612391Sjason@lowepower.com // test_brace_initialization 30712391Sjason@lowepower.com struct BraceInitialization { 30812391Sjason@lowepower.com int field1; 30912391Sjason@lowepower.com std::string field2; 31012391Sjason@lowepower.com }; 31112391Sjason@lowepower.com 31212391Sjason@lowepower.com py::class_<BraceInitialization>(m, "BraceInitialization") 31312391Sjason@lowepower.com .def(py::init<int, const std::string &>()) 31412391Sjason@lowepower.com .def_readwrite("field1", &BraceInitialization::field1) 31512391Sjason@lowepower.com .def_readwrite("field2", &BraceInitialization::field2); 31614299Sbbruce@ucdavis.edu // We *don't* want to construct using braces when the given constructor argument maps to a 31714299Sbbruce@ucdavis.edu // constructor, because brace initialization could go to the wrong place (in particular when 31814299Sbbruce@ucdavis.edu // there is also an `initializer_list<T>`-accept constructor): 31914299Sbbruce@ucdavis.edu py::class_<NoBraceInitialization>(m, "NoBraceInitialization") 32014299Sbbruce@ucdavis.edu .def(py::init<std::vector<int>>()) 32114299Sbbruce@ucdavis.edu .def_readonly("vec", &NoBraceInitialization::vec); 32212391Sjason@lowepower.com 32312391Sjason@lowepower.com // test_reentrant_implicit_conversion_failure 32412391Sjason@lowepower.com // #1035: issue with runaway reentrant implicit conversion 32512391Sjason@lowepower.com struct BogusImplicitConversion { 32612391Sjason@lowepower.com BogusImplicitConversion(const BogusImplicitConversion &) { } 32712391Sjason@lowepower.com }; 32812391Sjason@lowepower.com 32912391Sjason@lowepower.com py::class_<BogusImplicitConversion>(m, "BogusImplicitConversion") 33012391Sjason@lowepower.com .def(py::init<const BogusImplicitConversion &>()); 33112391Sjason@lowepower.com 33212391Sjason@lowepower.com py::implicitly_convertible<int, BogusImplicitConversion>(); 33314299Sbbruce@ucdavis.edu 33414299Sbbruce@ucdavis.edu // test_qualname 33514299Sbbruce@ucdavis.edu // #1166: nested class docstring doesn't show nested name 33614299Sbbruce@ucdavis.edu // Also related: tests that __qualname__ is set properly 33714299Sbbruce@ucdavis.edu struct NestBase {}; 33814299Sbbruce@ucdavis.edu struct Nested {}; 33914299Sbbruce@ucdavis.edu py::class_<NestBase> base(m, "NestBase"); 34014299Sbbruce@ucdavis.edu base.def(py::init<>()); 34114299Sbbruce@ucdavis.edu py::class_<Nested>(base, "Nested") 34214299Sbbruce@ucdavis.edu .def(py::init<>()) 34314299Sbbruce@ucdavis.edu .def("fn", [](Nested &, int, NestBase &, Nested &) {}) 34414299Sbbruce@ucdavis.edu .def("fa", [](Nested &, int, NestBase &, Nested &) {}, 34514299Sbbruce@ucdavis.edu "a"_a, "b"_a, "c"_a); 34614299Sbbruce@ucdavis.edu base.def("g", [](NestBase &, Nested &) {}); 34714299Sbbruce@ucdavis.edu base.def("h", []() { return NestBase(); }); 34814299Sbbruce@ucdavis.edu 34914299Sbbruce@ucdavis.edu // test_error_after_conversion 35014299Sbbruce@ucdavis.edu // The second-pass path through dispatcher() previously didn't 35114299Sbbruce@ucdavis.edu // remember which overload was used, and would crash trying to 35214299Sbbruce@ucdavis.edu // generate a useful error message 35314299Sbbruce@ucdavis.edu 35414299Sbbruce@ucdavis.edu struct NotRegistered {}; 35514299Sbbruce@ucdavis.edu struct StringWrapper { std::string str; }; 35614299Sbbruce@ucdavis.edu m.def("test_error_after_conversions", [](int) {}); 35714299Sbbruce@ucdavis.edu m.def("test_error_after_conversions", 35814299Sbbruce@ucdavis.edu [](StringWrapper) -> NotRegistered { return {}; }); 35914299Sbbruce@ucdavis.edu py::class_<StringWrapper>(m, "StringWrapper").def(py::init<std::string>()); 36014299Sbbruce@ucdavis.edu py::implicitly_convertible<std::string, StringWrapper>(); 36114299Sbbruce@ucdavis.edu 36214299Sbbruce@ucdavis.edu #if defined(PYBIND11_CPP17) 36314299Sbbruce@ucdavis.edu struct alignas(1024) Aligned { 36414299Sbbruce@ucdavis.edu std::uintptr_t ptr() const { return (uintptr_t) this; } 36514299Sbbruce@ucdavis.edu }; 36614299Sbbruce@ucdavis.edu py::class_<Aligned>(m, "Aligned") 36714299Sbbruce@ucdavis.edu .def(py::init<>()) 36814299Sbbruce@ucdavis.edu .def("ptr", &Aligned::ptr); 36914299Sbbruce@ucdavis.edu #endif 37012391Sjason@lowepower.com} 37112391Sjason@lowepower.com 37212391Sjason@lowepower.comtemplate <int N> class BreaksBase { public: virtual ~BreaksBase() = default; }; 37312391Sjason@lowepower.comtemplate <int N> class BreaksTramp : public BreaksBase<N> {}; 37412391Sjason@lowepower.com// These should all compile just fine: 37512391Sjason@lowepower.comtypedef py::class_<BreaksBase<1>, std::unique_ptr<BreaksBase<1>>, BreaksTramp<1>> DoesntBreak1; 37612391Sjason@lowepower.comtypedef py::class_<BreaksBase<2>, BreaksTramp<2>, std::unique_ptr<BreaksBase<2>>> DoesntBreak2; 37712391Sjason@lowepower.comtypedef py::class_<BreaksBase<3>, std::unique_ptr<BreaksBase<3>>> DoesntBreak3; 37812391Sjason@lowepower.comtypedef py::class_<BreaksBase<4>, BreaksTramp<4>> DoesntBreak4; 37912391Sjason@lowepower.comtypedef py::class_<BreaksBase<5>> DoesntBreak5; 38012391Sjason@lowepower.comtypedef py::class_<BreaksBase<6>, std::shared_ptr<BreaksBase<6>>, BreaksTramp<6>> DoesntBreak6; 38112391Sjason@lowepower.comtypedef py::class_<BreaksBase<7>, BreaksTramp<7>, std::shared_ptr<BreaksBase<7>>> DoesntBreak7; 38212391Sjason@lowepower.comtypedef py::class_<BreaksBase<8>, std::shared_ptr<BreaksBase<8>>> DoesntBreak8; 38312391Sjason@lowepower.com#define CHECK_BASE(N) static_assert(std::is_same<typename DoesntBreak##N::type, BreaksBase<N>>::value, \ 38412391Sjason@lowepower.com "DoesntBreak" #N " has wrong type!") 38512391Sjason@lowepower.comCHECK_BASE(1); CHECK_BASE(2); CHECK_BASE(3); CHECK_BASE(4); CHECK_BASE(5); CHECK_BASE(6); CHECK_BASE(7); CHECK_BASE(8); 38612391Sjason@lowepower.com#define CHECK_ALIAS(N) static_assert(DoesntBreak##N::has_alias && std::is_same<typename DoesntBreak##N::type_alias, BreaksTramp<N>>::value, \ 38712391Sjason@lowepower.com "DoesntBreak" #N " has wrong type_alias!") 38812391Sjason@lowepower.com#define CHECK_NOALIAS(N) static_assert(!DoesntBreak##N::has_alias && std::is_void<typename DoesntBreak##N::type_alias>::value, \ 38912391Sjason@lowepower.com "DoesntBreak" #N " has type alias, but shouldn't!") 39012391Sjason@lowepower.comCHECK_ALIAS(1); CHECK_ALIAS(2); CHECK_NOALIAS(3); CHECK_ALIAS(4); CHECK_NOALIAS(5); CHECK_ALIAS(6); CHECK_ALIAS(7); CHECK_NOALIAS(8); 39112391Sjason@lowepower.com#define CHECK_HOLDER(N, TYPE) static_assert(std::is_same<typename DoesntBreak##N::holder_type, std::TYPE##_ptr<BreaksBase<N>>>::value, \ 39212391Sjason@lowepower.com "DoesntBreak" #N " has wrong holder_type!") 39312391Sjason@lowepower.comCHECK_HOLDER(1, unique); CHECK_HOLDER(2, unique); CHECK_HOLDER(3, unique); CHECK_HOLDER(4, unique); CHECK_HOLDER(5, unique); 39412391Sjason@lowepower.comCHECK_HOLDER(6, shared); CHECK_HOLDER(7, shared); CHECK_HOLDER(8, shared); 39512391Sjason@lowepower.com 39612391Sjason@lowepower.com// There's no nice way to test that these fail because they fail to compile; leave them here, 39712391Sjason@lowepower.com// though, so that they can be manually tested by uncommenting them (and seeing that compilation 39812391Sjason@lowepower.com// failures occurs). 39912391Sjason@lowepower.com 40012391Sjason@lowepower.com// We have to actually look into the type: the typedef alone isn't enough to instantiate the type: 40112391Sjason@lowepower.com#define CHECK_BROKEN(N) static_assert(std::is_same<typename Breaks##N::type, BreaksBase<-N>>::value, \ 40212391Sjason@lowepower.com "Breaks1 has wrong type!"); 40312391Sjason@lowepower.com 40412391Sjason@lowepower.com//// Two holder classes: 40512391Sjason@lowepower.com//typedef py::class_<BreaksBase<-1>, std::unique_ptr<BreaksBase<-1>>, std::unique_ptr<BreaksBase<-1>>> Breaks1; 40612391Sjason@lowepower.com//CHECK_BROKEN(1); 40712391Sjason@lowepower.com//// Two aliases: 40812391Sjason@lowepower.com//typedef py::class_<BreaksBase<-2>, BreaksTramp<-2>, BreaksTramp<-2>> Breaks2; 40912391Sjason@lowepower.com//CHECK_BROKEN(2); 41012391Sjason@lowepower.com//// Holder + 2 aliases 41112391Sjason@lowepower.com//typedef py::class_<BreaksBase<-3>, std::unique_ptr<BreaksBase<-3>>, BreaksTramp<-3>, BreaksTramp<-3>> Breaks3; 41212391Sjason@lowepower.com//CHECK_BROKEN(3); 41312391Sjason@lowepower.com//// Alias + 2 holders 41412391Sjason@lowepower.com//typedef py::class_<BreaksBase<-4>, std::unique_ptr<BreaksBase<-4>>, BreaksTramp<-4>, std::shared_ptr<BreaksBase<-4>>> Breaks4; 41512391Sjason@lowepower.com//CHECK_BROKEN(4); 41612391Sjason@lowepower.com//// Invalid option (not a subclass or holder) 41712391Sjason@lowepower.com//typedef py::class_<BreaksBase<-5>, BreaksTramp<-4>> Breaks5; 41812391Sjason@lowepower.com//CHECK_BROKEN(5); 41912391Sjason@lowepower.com//// Invalid option: multiple inheritance not supported: 42012391Sjason@lowepower.com//template <> struct BreaksBase<-8> : BreaksBase<-6>, BreaksBase<-7> {}; 42112391Sjason@lowepower.com//typedef py::class_<BreaksBase<-8>, BreaksBase<-6>, BreaksBase<-7>> Breaks8; 42212391Sjason@lowepower.com//CHECK_BROKEN(8); 423