Skip to content

Commit 485ea48

Browse files
authored
Merge pull request #224 from robotpy/template-base
Ensure template classes are instantiated in correct order
2 parents ccce032 + e6449d0 commit 485ea48

File tree

6 files changed

+68
-18
lines changed

6 files changed

+68
-18
lines changed

robotpy_build/autowrap/cxxparser.py

Lines changed: 22 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1987,19 +1987,29 @@ def parse_header(
19871987
if doc_add:
19881988
doc_add = f"\n{doc_add}"
19891989

1990-
hctx.template_instances.append(
1991-
TemplateInstanceContext(
1992-
scope_var=visitor._get_module_var(tmpl_data),
1993-
var_name=f"tmplCls{i}",
1994-
py_name=k,
1995-
full_cpp_name_identifier=qualname,
1996-
binder_typename=f"bind_{qualname}_{i}",
1997-
params=tmpl_data.params,
1998-
header_name=f"{qualname}.hpp",
1999-
doc_set=visitor._quote_doc(tmpl_data.doc),
2000-
doc_add=visitor._quote_doc(doc_add),
2001-
)
1990+
tctx = TemplateInstanceContext(
1991+
scope_var=visitor._get_module_var(tmpl_data),
1992+
var_name=f"tmplCls{i}",
1993+
py_name=k,
1994+
full_cpp_name_identifier=qualname,
1995+
binder_typename=f"bind_{qualname}_{i}",
1996+
params=tmpl_data.params,
1997+
header_name=f"{qualname}.hpp",
1998+
doc_set=visitor._quote_doc(tmpl_data.doc),
1999+
doc_add=visitor._quote_doc(doc_add),
20022000
)
2001+
hctx.template_instances.append(tctx)
2002+
2003+
# Ensure that template instances are created in class order if the
2004+
# template class is in this header file
2005+
# - not matching here is not an error
2006+
qualname_match = tmpl_data.qualname.lstrip(":")
2007+
for cctx in hctx.classes:
2008+
if cctx.dep_cpp_name.lstrip(":") == qualname_match:
2009+
assert cctx.template
2010+
tctx.matched = True
2011+
cctx.template.instances.append(tctx)
2012+
break
20032013

20042014
for param in tmpl_data.params:
20052015
visitor._add_user_type_caster(param)

robotpy_build/autowrap/header.cpp.j2

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -64,13 +64,19 @@ struct rpybuild_{{ hname }}_initializer {
6464
{% endfor %}
6565

6666
{# template decls #}
67-
{% for tmpl_data in template_instances %}
67+
{% for tmpl_data in template_instances if not tmpl_data.matched %}
6868
rpygen::{{ tmpl_data.binder_typename }} {{ tmpl_data.var_name }};
6969
{% endfor %}
7070

7171
{# class decls #}
72-
{%- for cls in classes if not cls.template %}
73-
{{ pybind11.cls_decl(cls) }}
72+
{%- for cls in classes %}
73+
{% if not cls.template -%}
74+
{{ pybind11.cls_decl(cls) }}
75+
{%- else -%}
76+
{%- for tmpl_data in cls.template.instances %}
77+
rpygen::{{ tmpl_data.binder_typename }} {{ tmpl_data.var_name }};
78+
{% endfor -%}
79+
{%- endif -%}
7480
{% endfor %}
7581

7682
py::module &m;
@@ -86,12 +92,18 @@ struct rpybuild_{{ hname }}_initializer {
8692
enum{{ loop.index }}{{ pybind11.enum_init(enum.scope_var, enum) }},
8793
{% endfor %}
8894

89-
{% for tmpl_data in template_instances %}
95+
{% for tmpl_data in template_instances if not tmpl_data.matched %}
9096
{{ tmpl_data.var_name }}({{ tmpl_data.scope_var }}, "{{ tmpl_data.py_name }}"),
9197
{% endfor %}
9298

93-
{% for cls in classes if not cls.template %}
94-
{{ pybind11.cls_init(cls, '"' + cls.py_name + '"') }}
99+
{% for cls in classes %}
100+
{% if not cls.template -%}
101+
{{ pybind11.cls_init(cls, '"' + cls.py_name + '"') }}
102+
{%- else -%}
103+
{%- for tmpl_data in cls.template.instances %}
104+
{{ tmpl_data.var_name }}({{ tmpl_data.scope_var }}, "{{ tmpl_data.py_name }}"),
105+
{% endfor -%}
106+
{%- endif %}
95107
{% endfor %}
96108

97109
m(m)

robotpy_build/autowrap/j2_context.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -353,6 +353,9 @@ class ClassTemplateData:
353353
#: the specified C++ code is inserted into the template definition
354354
inline_code: str
355355

356+
#: Instances of this class
357+
instances: typing.List["TemplateInstanceContext"] = field(default_factory=list)
358+
356359

357360
@dataclass
358361
class ClassContext:
@@ -493,6 +496,9 @@ class TemplateInstanceContext:
493496
doc_set: Documentation
494497
doc_add: Documentation
495498

499+
#: If true, instantiated in class order
500+
matched: bool = False
501+
496502

497503
@dataclass
498504
class HeaderContext:
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
classes:
2+
TDBase:
3+
TDChild:
4+
template_params:
5+
- T
6+
7+
templates:
8+
TDChild:
9+
qualname: TDChild
10+
params:
11+
- int

tests/cpp/pyproject.toml.tmpl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,7 @@ generate = [
101101
{tvchild = "templates/tvchild.h"},
102102

103103
{tbasic = "templates/basic.h"},
104+
{tdependent_base = "templates/dependent_base.h"},
104105
{tdependent_param = "templates/dependent_param.h"},
105106
{tdependent_using = "templates/dependent_using.h"},
106107
{tdependent_using2 = "templates/dependent_using2.h"},
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
#pragma once
2+
3+
// Template class that has a non-template base class in the same file
4+
5+
struct TDBase {
6+
virtual ~TDBase() {}
7+
};
8+
9+
template <typename T>
10+
struct TDChild : TDBase {};

0 commit comments

Comments
 (0)