# Using CGraph TemplateNode for Parameterized and Reusable Nodes

> Unlock reusable, type-safe pipeline components with CGraph TemplateNode. Create parameterized nodes with zero runtime overhead for efficient C++ graph processing.

- Repository: [Chunel/cgraph](https://github.com/chunelfeng/cgraph)
- Tags: how-to-guide
- Published: 2026-02-27

---

**CGraph's `GTemplateNode` class enables compile-time parameterized nodes that maintain full `GNode` compatibility, allowing developers to create type-safe, reusable pipeline components with zero runtime overhead.**

The `chunelfeng/cgraph` library provides a powerful templating mechanism for building parameterized and reusable nodes in CGraph pipelines. Unlike standard `GNode` instances, template nodes accept variadic compile-time arguments that enable generic programming patterns while integrating seamlessly with the engine's scheduling and dependency analysis systems.

## What Is GTemplateNode in CGraph?

`GTemplateNode` is a thin variadic-template wrapper defined in [`src/GraphCtrl/GraphElement/GNode/GTemplateNode.h`](https://github.com/chunelfeng/cgraph/blob/main/src/GraphCtrl/GraphElement/GNode/GTemplateNode.h). It inherits directly from `GNode` and adds no new runtime behavior. Instead, it serves as a type-safe carrier for compile-time parameters (types, constants, or sizes) that are forwarded to derived classes during construction.

The template parameters are used strictly for static type checking and constructor argument forwarding. Once instantiated, the node behaves exactly like any other `GNode` in the pipeline.

### Core Architecture Components

| Component | Role | Source Location |
|-----------|------|-----------------|
| `GElement` | Abstract base class for all pipeline elements. | [`src/GraphCtrl/GraphElement/GElement/GElement.h`](https://github.com/chunelfeng/cgraph/blob/main/src/GraphCtrl/GraphElement/GElement/GElement.h) |
| `GNode` | Concrete element implementing the `run()` method. | [`src/GraphCtrl/GraphElement/GNode/GNode.h`](https://github.com/chunelfeng/cgraph/blob/main/src/GraphCtrl/GraphElement/GNode/GNode.h) |
| `GTemplateNode<Args…>` | Variadic template wrapper enabling compile-time parameterization. | [`src/GraphCtrl/GraphElement/GNode/GTemplateNode.h`](https://github.com/chunelfeng/cgraph/blob/main/src/GraphCtrl/GraphElement/GNode/GTemplateNode.h) |
| `GPipeline` | Orchestrator providing `registerGElement` and `registerGNode` overloads for template nodes. | [`src/GraphCtrl/GraphPipeline/GPipeline.h`](https://github.com/chunelfeng/cgraph/blob/main/src/GraphCtrl/GraphPipeline/GPipeline.h) (lines 70-75) |
| `GPipeline.inl` | Implementation of template-node registration logic using perfect forwarding. | `src/GraphCtrl/GraphPipeline/GPipeline.inl` (lines 77-91) |

## Benefits of Using TemplateNode for Parameterized Nodes

- **Parameterized Reuse**: A single class definition can be instantiated with different compile-time arguments (e.g., `MyTemplateNode<int,float>` vs. `MyTemplateNode<int>`) without code duplication.
- **Zero Runtime Overhead**: All template parameters are resolved at compile time. The engine treats the node as a standard `GNode` with no special-case handling or virtual dispatch penalties.
- **Clean API**: Constructor arguments are passed directly in `registerGElement` or `registerGNode` calls, eliminating the need for factory functions or `void*` user data patterns.
- **Strong Type Safety**: The registration overloads use `c_enable_if_t<std::is_base_of<GTemplateNode<Args…>, TNode>::value>` guards (defined in [`GPipeline.h`](https://github.com/chunelfeng/cgraph/blob/main/GPipeline.h)) to prevent accidental registration of non-template nodes with template-specific overloads.

## How to Create and Register a TemplateNode

### Step 1: Define Your Templated Node

Create a class that inherits from `CGraph::GTemplateNode<Args…>` and implement custom constructors to receive runtime data. The template parameters enable compile-time specialization while the constructors handle dynamic initialization.

```cpp
// tutorial/MyGNode/MyTemplateNode.h
#ifndef CGRAPH_MYTEMPLATENODE_H
#define CGRAPH_MYTEMPLATENODE_H

#include "CGraph.h"

template <typename ...Args>
class MyTemplateNode : public CGraph::GTemplateNode<Args...> {
public:
    // Constructor for (int, float) signature
    explicit MyTemplateNode(int num, float score) {
        num_   = num;
        score_ = score;
    }

    // Constructor for single int argument
    explicit MyTemplateNode(int num) {
        num_   = num;
        score_ = 7.0f;   // default value
    }

    CStatus run() override {
        CGraph::CGRAPH_ECHO("[MyTemplateNode] num = %d, score = %f", num_, score_);
        return CStatus();
    }

private:
    int   num_;
    float score_;
};

#endif // CGRAPH_MYTEMPLATENODE_H

```

### Step 2: Register Nodes with the Pipeline

Use `registerGElement` with explicit template arguments to instantiate your node. The pipeline forwards constructor arguments via perfect forwarding implemented in `GPipeline.inl` (lines 77-91).

```cpp
// tutorial/T08-Template.cpp
#include "MyGNode/MyTemplateNode.h"
#include "MyGNode/MyTemplateV2Node.h"

using namespace CGraph;

void tutorial_template() {
    GPipelinePtr pipeline = GPipelineFactory::create();

    // Pointers to receive created nodes
    GTemplateNodePtr<int,float> a = nullptr;
    GTemplateNodePtr<int,float> b = nullptr;
    GTemplateNodePtr<int>       c = nullptr;
    GElementPtr                d = nullptr;

    // Register with different constructor signatures
    pipeline->registerGElement<MyTemplateNode<int,float>>(&a, {}, 3, 3.5f);
    pipeline->registerGElement<MyTemplateNode<int,float>>(&b, {a}, 5, 3.75f);
    pipeline->registerGElement<MyTemplateNode<int>>(&c, {b}, 8);

    // Register node with non-type template parameter
    pipeline->registerGElement<MyTemplateV2Node<4>>(&d, {c});

    pipeline->process();
    GPipelineFactory::remove(pipeline);
}

```

### Step 3: Using the registerGNode Shortcut

If you do not need the raw pointer for later dependency references, use `registerGNode` (defined in `GPipeline.inl`, lines 67-74) to receive the concrete node directly:

```cpp
auto *nodeA = pipeline->registerGNode<MyTemplateNode<int,float>>({},
                                                            3, 3.5f);
auto *nodeB = pipeline->registerGNode<MyTemplateNode<int,float>>({nodeA},
                                                            5, 3.75f);

```

This shortcut forwards to `registerGElement` internally but returns the pointer rather than requiring an output parameter.

## Key Implementation Files

| File | Purpose | Location |
|------|---------|----------|
| [`GTemplateNode.h`](https://github.com/chunelfeng/cgraph/blob/main/GTemplateNode.h) | Defines the variadic template base class `GTemplateNode<Args…>` and the `GTemplateNodePtr` alias. | [`src/GraphCtrl/GraphElement/GNode/GTemplateNode.h`](https://github.com/chunelfeng/cgraph/blob/main/src/GraphCtrl/GraphElement/GNode/GTemplateNode.h) |
| [`GPipeline.h`](https://github.com/chunelfeng/cgraph/blob/main/GPipeline.h) | Declares template overloads for `registerGElement` and `registerGNode` with type safety guards. | [`src/GraphCtrl/GraphPipeline/GPipeline.h`](https://github.com/chunelfeng/cgraph/blob/main/src/GraphCtrl/GraphPipeline/GPipeline.h) (lines 70-75) |
| `GPipeline.inl` | Implements perfect forwarding of constructor arguments during template node registration. | `src/GraphCtrl/GraphPipeline/GPipeline.inl` (lines 67-91) |
| [`MyTemplateNode.h`](https://github.com/chunelfeng/cgraph/blob/main/MyTemplateNode.h) | Tutorial example showing custom constructors and runtime parameter handling. | [`tutorial/MyGNode/MyTemplateNode.h`](https://github.com/chunelfeng/cgraph/blob/main/tutorial/MyGNode/MyTemplateNode.h) |
| [`T08-Template.cpp`](https://github.com/chunelfeng/cgraph/blob/main/T08-Template.cpp) | End-to-end demonstration of multiple template instantiations and dependency chaining. | [`tutorial/T08-Template.cpp`](https://github.com/chunelfeng/cgraph/blob/main/tutorial/T08-Template.cpp) |

## Summary

- **GTemplateNode** is a zero-overhead wrapper in [`GTemplateNode.h`](https://github.com/chunelfeng/cgraph/blob/main/GTemplateNode.h) that enables compile-time parameterization while maintaining full `GNode` compatibility.
- **Type safety** is enforced at compile time through `std::is_base_of` checks in [`GPipeline.h`](https://github.com/chunelfeng/cgraph/blob/main/GPipeline.h), preventing mismatched registrations.
- **Constructor forwarding** in `GPipeline.inl` (lines 77-91) allows runtime arguments to be passed directly during registration without factory boilerplate.
- **Reusability** is achieved by instantiating the same class with different template arguments (e.g., `MyTemplateNode<int,float>` vs. `MyTemplateNode<int>`).
- **Integration** with existing pipelines is seamless because template nodes are stored as `GTemplateNodePtr` but treated as standard `GElement` instances during execution.

## Frequently Asked Questions

### What is the difference between GNode and GTemplateNode?

`GNode` is the concrete base class for all executable nodes in CGraph, providing the virtual `run()` method and dependency management. `GTemplateNode<Args…>` is a thin variadic-template wrapper defined in [`src/GraphCtrl/GraphElement/GNode/GTemplateNode.h`](https://github.com/chunelfeng/cgraph/blob/main/src/GraphCtrl/GraphElement/GNode/GTemplateNode.h) that inherits from `GNode` and adds compile-time parameterization without introducing new runtime behavior or virtual functions.

### Can I use non-type template parameters with GTemplateNode?

Yes. The variadic template design supports any compile-time constant, including non-type parameters. For example, `MyTemplateV2Node<4>` (as shown in [`tutorial/T08-Template.cpp`](https://github.com/chunelfeng/cgraph/blob/main/tutorial/T08-Template.cpp)) passes the integer `4` as a template argument, allowing the node to use that value in constexpr contexts or as a fixed array size.

### Does using GTemplateNode add runtime overhead?

No. `GTemplateNode` is a zero-cost abstraction. All template parameters are resolved at compile time, and the `GPipeline` engine stores and schedules these nodes exactly like standard `GNode` instances. The registration logic in `src/GraphCtrl/GraphPipeline/GPipeline.inl` uses perfect forwarding to construct the object in place without additional indirection or heap allocation overhead.

### How do I pass dependencies when registering a TemplateNode?

Dependencies are passed as the second argument to `registerGElement` or `registerGNode` using an initializer list or vector of `GElementPtr`. For example: `pipeline->registerGElement<MyTemplateNode<int,float>>(&b, {a}, 5, 3.75f);` registers node `b` with `a` as its dependency, while the remaining arguments (`5, 3.75f`) are forwarded to the constructor defined in your derived class.