Skip to content

Instantly share code, notes, and snippets.

@mosioc
Last active December 26, 2025 15:43
Show Gist options
  • Select an option

  • Save mosioc/a7da7681dd575ddea6f54776529bddd9 to your computer and use it in GitHub Desktop.

Select an option

Save mosioc/a7da7681dd575ddea6f54776529bddd9 to your computer and use it in GitHub Desktop.
Inja Cpp Template Engine Reference

Inja C++ Template Engine Reference

Inja is a modern C++ template engine inspired by Jinja2, designed for rendering dynamic text using JSON data. It’s lightweight, header-only, and integrates seamlessly with C++ projects. This expanded reference provides a comprehensive guide to Inja’s features, syntax, and advanced usage, including detailed explanations of control structures, logical operators, and additional template features.

Table of Contents

Overview

  • Jinja2-inspired syntax for templates.
  • Header-only, dependency-light (requires nlohmann/json).
  • Supports variables, loops, conditionals, filters, functions, comments, and custom callbacks.
  • Fast, memory-efficient, and suitable for both simple and complex templating needs.

Setup

Inja is header-only and requires the nlohmann/json library. Include it in your project:

  1. Add Dependencies:

  2. CMake Example:

find_package(nlohmann_json REQUIRED)
add_executable(myapp main.cpp)
target_include_directories(myapp PRIVATE /path/to/inja/include)
target_link_libraries(myapp PRIVATE nlohmann_json::nlohmann_json)
  1. C++ Includes:
#include <inja/inja.hpp>
#include <nlohmann/json.hpp>

Basic Usage

Render a template with JSON data using Inja’s core components: inja::Environment and nlohmann::json.

Example:

#include <inja/inja.hpp>
#include <nlohmann/json.hpp>
#include <iostream>

int main() {
    inja::Environment env;
    nlohmann::json data;
    data["name"] = "World";

    std::string result = env.render("Hello {{ name }}!", data);
    std::cout << result << std::endl; // Outputs: Hello World!
    return 0;
}
  • inja::Environment: Manages template parsing and rendering.
  • nlohmann::json: Stores data for template substitution.
  • env.render: Renders a template string with JSON data.

Template Syntax

Inja uses Jinja2-like syntax for templates, supporting variables, control structures, filters, functions, and comments.

Variables

Access JSON data using {{ variable }}.

Hello {{ name }}!

Nested access:

{{ user.address.city }}

Safe access with default:

{{ user.address.city | default("Unknown") }}

Control Structures

Inja supports advanced control structures for dynamic template rendering.

Set Statements

The set statement assigns values to variables within a template, useful for temporary calculations or formatting.

Syntax:

{% set variable = value %}

Example:

{% set greeting = "Hello, " + name %}
{{ greeting }}!  {# Outputs: Hello, World! #}

You can also set multiple variables:

{% set first_name = "John" %}
{% set last_name = "Doe" %}
{{ first_name }} {{ last_name }}  {# Outputs: John Doe #}

You can also use the set statement to define object-style variables directly inside a template. This is useful for encapsulating structured data like server configurations:

{% set server_list = {
  "server_name": "Test",
  "download_url": "https://localhost:8443/downloading",
  "upload_url": "https://localhost:8443/upload"
} %}

#### If Statements
Conditionals control template output based on boolean expressions.

Syntax:
```jinja
{% if condition %}
  True case
{% elif another_condition %}
  Another case
{% else %}
  False case
{% endif %}

Example:

{% if age >= 18 %}
  Adult
{% elif age >= 13 %}
  Teen
{% else %}
  Child
{% endif %}

Nested conditionals:

{% if user.is_active %}
  {% if user.role == "admin" %}
    Admin Dashboard
  {% else %}
    User Dashboard
  {% endif %}
{% else %}
  Please log in
{% endif %}

For Loops

Loops iterate over arrays or objects in JSON data.

Syntax:

{% for item in list %}
  {{ item }}
{% endfor %}

Example:

<ul>
{% for user in users %}
  <li>{{ user.name }} ({{ user.email }})</li>
{% endfor %}
</ul>

Loop over object properties:

{% for key, value in user %}
  {{ key }}: {{ value }}
{% endfor %}

Loop variables:

  • loop.index: 1-based index (starts at 1).
  • loop.index0: 0-based index (starts at 0).
  • loop.first: True if first iteration.
  • loop.last: True if last iteration.

Example:

{% for item in items %}
  {% if loop.first %}
    First item: {{ item }}
  {% elif loop.last %}
    Last item: {{ item }}
  {% else %}
    Item {{ loop.index }}: {{ item }}
  {% endif %}
{% endfor %}

Logical Operators

Inja supports logical operators for complex conditions:

  • and: True if both operands are true.
  • or: True if at least one operand is true.
  • not: Negates a condition.
  • Parentheses (): Group expressions for precedence.

Example:

{% if age >= 18 and user.is_active %}
  Active adult user
{% endif %}

{% if role == "admin" or role == "editor" %}
  Authorized user
{% endif %}

{% if not user.is_blocked %}
  Access granted
{% endif %}

{% if (age >= 18 or role == "admin") and user.is_active %}
  Special access
{% endif %}

Filters

Filters transform data: {{ variable | filter }}.

Common filters:

  • upper: Convert to uppercase.
  • lower: Convert to lowercase.
  • default(value): Use default if variable is missing.
  • join(sep): Join array elements with separator.
  • length: Get length of string or array.
  • trim: Remove leading/trailing whitespace.
  • replace(old, new): Replace occurrences of a string.
  • sort: Sort an array.

Example:

{{ name | upper }}  {# WORLD #}
{{ items | join(", ") }}  {# item1, item2, item3 #}
{{ missing | default("N/A") }}  {# N/A #}
{{ text | trim }}  {# Removes whitespace #}
{{ text | replace("hello", "hi") }}  {# Replaces 'hello' with 'hi' #}
{{ numbers | sort }}  {# Sorts array in ascending order #}

Functions

Inja supports built-in functions for dynamic operations:

  • range(n): Generate array [0, 1, ..., n-1].
  • is_type: Check JSON type (e.g., is_string, is_number, is_array, is_object).
  • exists: Check if variable exists.
  • existsIn(object, key): Check if a key exists in an object.
  • first: Get first element of an array.
  • last: Get last element of an array.

Example:

{% for i in range(3) %}
  {{ i }}  {# Outputs: 0 1 2 #}
{% endfor %}

{% if is_string(name) %}
  Name is a string
{% endif %}

{% if exists("user") %}
  User exists
{% endif %}

{{ items | first }}  {# First item of array #}

Comments

Template comments are ignored during rendering.

Syntax:

{# This is a comment #}

Multi-line comments:

{# This is a
   multi-line comment #}

Example:

{# Display user info #}
{{ name }} {# Renders name, comment is ignored #}

C++ Integration

Loading Templates

Load templates from strings or files.

From string:

std::string result = env.render("Hello {{ name }}!", data);

From file:

inja::Environment env;
env.set_search_path("/path/to/templates");
std::string result = env.render_file("template.html", data);

Error Handling

Handle parsing and rendering errors with try-catch.

Example:

try {
    std::string result = env.render("{{ undefined }}", data);
} catch (const inja::InjaError& e) {
    std::cerr << "Inja error: " << e.what() << std::endl;
} catch (const nlohmann::json::exception& e) {
    std::cerr << "JSON error: " << e.what() << std::endl;
}

Custom Configuration

Customize delimiters or other settings.

Example:

inja::Environment env;
env.set_statement("<%", "%>"); // Change statement delimiters
env.set_expression("[[", "]]"); // Change variable delimiters
env.set_comment("{#", "#}"); // Change comment delimiters

Disable whitespace trimming:

env.set_trim_blocks(false);
env.set_lstrip_blocks(false);

Custom Callbacks

Extend Inja with custom filters and functions.

Custom Filters

Add a filter to transform data.

Example:

env.add_callback("double", 1, [](inja::Arguments& args) {
    double value = args.at(0)->get<double>();
    return value * 2.0;
});

Usage:

{{ 5 | double }}  {# Outputs: 10 #}

Custom Functions

Add a function for custom logic.

Example:

env.add_callback("greet", 1, [](inja::Arguments& args) {
    std::string name = args.at(0)->get<std::string>();
    return "Hello, " + name + "!";
});

Usage:

{{ greet(name) }}  {# Outputs: Hello, World! #}

Multiple arguments:

env.add_callback("sum", 2, [](inja::Arguments& args) {
    double a = args.at(0)->get<double>();
    double b = args.at(1)->get<double>();
    return a + b;
});

Usage:

{{ sum(3, 4) }}  {# Outputs: 7 #}

Best Practices

  • Validate JSON Data: Ensure JSON data is complete to avoid runtime errors.
  • Use Error Handling: Always wrap render calls in try-catch blocks.
  • Modular Templates: Use {% include %} for reusable template components.
  • Optimize Filters: Avoid complex logic in templates; use C++ callbacks for heavy computation.
  • Sanitize Inputs: Escape user inputs to prevent injection attacks (use escape filter if available).
  • Test Templates: Test templates with edge cases (empty arrays, missing keys).

Resources

  • Official Inja Documentation: GitHub
  • nlohmann/json Documentation: GitHub
  • Jinja2 Documentation (for syntax inspiration): Jinja2 Docs
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment