@@ -38,6 +38,30 @@ void bind_classes_module(py::module&&m) {
3838 .def (" g" , &demo::Foo::Child::g);
3939 }
4040
41+ // Cross-reference / "cyclic" test case (issue #231, PR #275):
42+ // Registration order: ParticleContainer, then ParIter, then ParIterBase.
43+ // ParticleContainer.Iterator is an alias to ParIter (cross-ref).
44+ // ParIter inherits ParIterBase and takes ParticleContainer in __init__.
45+ // The topological sort must put ParIterBase before ParIter;
46+ // from __future__ import annotations handles the annotation back-refs.
47+ {
48+ auto pyParIterBase = py::class_<demo::ParIterBase>(m, " ParIterBase" );
49+ pyParIterBase.def_readwrite (" level" , &demo::ParIterBase::level);
50+
51+ auto pyParticleContainer = py::class_<demo::ParticleContainer>(m, " ParticleContainer" );
52+ pyParticleContainer.def_readwrite (" name" , &demo::ParticleContainer::name);
53+
54+ auto pyParIter = py::class_<demo::ParIter, demo::ParIterBase>(m, " ParIter" );
55+ pyParIter.def (py::init<demo::ParticleContainer&, int >(),
56+ py::arg (" particle_container" ), py::arg (" level" ));
57+
58+ // Bind after ParIter is registered so pybind11 resolves the Python type
59+ pyParticleContainer.def (" process" , &demo::ParticleContainer::process);
60+
61+ // Alias: ParticleContainer.Iterator = ParIter
62+ pyParticleContainer.attr (" Iterator" ) = pyParIter;
63+ }
64+
4165 {
4266 py::register_exception<demo::CppException>(m, " CppException" );
4367 }
0 commit comments