Files
cpp-templates/README.md
2026-03-13 13:43:28 -04:00

4.2 KiB

TypeFactory

A lightweight registry-based factory for creating objects by runtime identifier.

TypeFactory is a small header-only C++ utility for situations where the exact object type must be selected dynamically at runtime using an ID.

Typical use cases include:

  • protocol command dispatch
  • vehicle type identification
  • runtime parser or handler selection
  • plugin-like object creation
  • configuration-based object instantiation

The implementation is intentionally simple and follows the KISS principle.

Features

  • header-only implementation
  • C++17 compatible
  • compile-time validation of registered types
  • fast lookup using std::unordered_map
  • optional access to creator function for advanced use
  • predictable and compact API
  • suitable for both commercial and open-source projects

Requirements

  • C++17 or newer
  • ClassId must be hashable (std::hash<ClassId> must be available)

Basic Idea

The factory stores a mapping:

  • runtime ID -> creator function

A derived type is registered once, then can be created later by its ID.

Example

#include "typefactory.h"
#include <string>
#include <memory>

struct Base {
    virtual ~Base() = default;
    virtual int get() = 0;
};

struct Derived1 : Base {
    explicit Derived1(int start) : m_start(start) {}
    int get() override {
        return m_start + 1;
    }
private:
    int m_start = 0;
};

struct Derived2 : Base {
    explicit Derived2(int start) : m_start(start) {}
    int get() override {
        return m_start + 2;
    }
private:
    int m_start = 0;
};

int main() {
    TypeFactory<std::string, Base, int> factory;

    factory.registerType<Derived1>("one");
    factory.registerType<Derived2>("two");

    auto d1 = factory.create("one", 10);
    auto d2 = factory.create("two", 10);

    return d1->get() + d2->get();
}

Advanced Usage

The factory also provides direct access to the creator function:

auto fn = factory.creator("one");
auto obj = fn(10);

This can be useful when integrating with dispatch tables or higher-level runtime logic.

API Overview

registerType

Registers a derived type for a given runtime ID.

factory.registerType<Derived>("id");

Compile-time checks ensure that:

  • Derived inherits from BaseClass
  • Derived is constructible from Args...

If the same ID is registered again, the previous registration is overwritten. This is intentional: last registration wins.

creator

Returns the creator function associated with the given ID.

auto fn = factory.creator("id");

Throws std::out_of_range if the ID is not registered.

create

Creates an object directly by ID.

auto obj = factory.create("id", args...);

Throws std::out_of_range if the ID is not registered.

contains

Checks whether an ID is registered.

if (factory.contains("id")) {
    // safe to create
}

Design Notes

  • TypeFactory is not thread-safe during registration.
  • Types should normally be registered during initialization.
  • Lookup and creation are lightweight and predictable.
  • The class is designed to be reusable as a low-level infrastructure utility.
  • The registry is stored in a protected std::unordered_map, so derived factories can extend the design if needed.

Why Not Abstract Factory?

This utility is not a classic Abstract Factory pattern.

A classic Abstract Factory typically creates families of related objects.

TypeFactory is closer to a:

  • registry-based factory
  • type factory
  • runtime creator map

It focuses on selecting one concrete type by runtime ID.

Example Use Cases

Vehicle Identification

A controller returns a vehicle ID.
The system uses that ID to create the matching parameter or settings object.

Protocol Command Handling

A command ID is received over the network.
The system selects and creates the correct handler object for that command.

Runtime Format Selection

A parser or converter is selected dynamically depending on file type, message type, or configuration.

License

This project is licensed under the MIT License.

For source files, it is recommended to use SPDX headers such as:

// SPDX-License-Identifier: MIT
// Copyright (c) 2025 Dim Himro