diff --git a/cxxheaderparser/parser.py b/cxxheaderparser/parser.py index da55c6a..1b53429 100644 --- a/cxxheaderparser/parser.py +++ b/cxxheaderparser/parser.py @@ -1864,7 +1864,8 @@ def _parse_function( self.visitor.on_class_method(state, method) else: assert isinstance(state, (ExternBlockState, NamespaceBlockState)) - if not method.has_body: + # only template specializations can be declared without a body here + if not method.has_body and not method.template: raise self._parse_error(None, expected="Method body") self.visitor.on_method_impl(state, method) diff --git a/tests/test_template.py b/tests/test_template.py index 4bea435..478f814 100644 --- a/tests/test_template.py +++ b/tests/test_template.py @@ -1987,3 +1987,43 @@ def test_extern_template() -> None: }, ) ) + + +def test_fwd_declared_method() -> None: + content = """ + // forward declaration for specialized template function + template <> Clazz::Clazz(); + """ + data = parse_string(content, cleandoc=True) + + assert data == ParsedData( + namespace=NamespaceScope( + method_impls=[ + Method( + return_type=None, + name=PQName( + segments=[ + NameSpecifier( + name="Clazz", + specialization=TemplateSpecialization( + args=[ + TemplateArgument( + arg=Type( + typename=PQName( + segments=[NameSpecifier(name="A")] + ) + ) + ) + ] + ), + ), + NameSpecifier(name="Clazz"), + ] + ), + parameters=[], + template=TemplateDecl(), + constructor=True, + ) + ] + ) + )