class {{ c_type_name }} : public ASTBase {
public:
    {{ c_type_name }}() = default;
    {{ c_type_name }}({{ c_type_name }} const &x) = default;
    {{ c_type_name }}({{ c_type_name }} &&x) noexcept = default;
    auto operator=({{ c_type_name }} const &x) -> {{ c_type_name }}& = default;
    auto operator=({{ c_type_name }} &&x) noexcept -> {{ c_type_name }}& = default;
    ~{{ c_type_name }}() noexcept = default;
{% for argument_name, argument in type.arguments.items() -%}
{%- if argument.type == 'location' %}
    auto {{ argument_name }}() -> Location;
{%- elif argument.type == 'string' %}
    auto {{ argument_name }}() -> std::string_view;
{%- elif argument.type == 'number' %}
    auto {{ argument_name }}() -> int;
{%- elif argument.type == 'bool' %}
    auto {{ argument_name }}() -> bool;
{%- elif argument.type == 'symbol' %}
    auto {{ argument_name }}() -> Symbol;
{%- elif argument.type == 'string_array' %}
    auto {{ argument_name }}() -> std::vector<std::string_view>;
{%- else %}
    auto {{ argument_name }}() -> {{ argument.type | camel }};
{%- endif %}
{%- endfor %}

    void visit(py::handle visitor, py::args const &args, py::kwargs const &kwargs);
    auto transform(Library &lib, py::handle transform, py::args const &args, py::kwargs const &kwargs) -> std::optional<{{ c_type_name }}>;
    auto update(Library &lib, py::kwargs const &kwargs) -> {{ c_type_name }};

    static auto construct(Library &lib{% for argument_name, argument in type.arguments.items() %}, {{ argument.type | cpar }}{{ argument_name }}{% endfor %}) -> {{ c_type_name }};
    static auto acquire(clingo_ast_t *ast) -> {{ c_type_name }} {
        return {ast};
    }

    friend auto operator==({{ c_type_name }} const &a, {{ c_type_name }} const &b) -> bool = default;
    friend auto operator<=>({{ c_type_name }} const &a, {{ c_type_name }} const &b) -> std::strong_ordering = default;

private:
    {{ c_type_name }}(clingo_ast_t *ast) : ASTBase{ast} { }
};
