Lean Template via Composite Construction

Vladimir Sakharuk 1 min read
programming

I’ve found this composite template pattern useful. It replaces common nested if-else chains with leaner logic—handy in heavily templated applications.

The core idea is a nested function that detects one type, then delegates the rest of the detection to the chain. It passes the detected type as the resolved value, supports multiple detection layers, and handles different configuration implementations.

soul.cpp
cpp
template<typename... Choices>
std::unique_ptr<Base> deduceFirst(std::string_view config)
{
    std::unique_ptr<Base> composite;
    ([&] {
        if(Choices::amI(config[0]))
        {   
            composite = std::move(deduceSecond<Choices, Choices...>(config));
            return true;
        }
        return false;
    }()
    || ...);
    return composite;
}

Below is a full example that constructs a composite class with different parameters based on configuration:

a.cpp
cpp
#include <iostream>
#include <string_view>
#include <memory>

struct A {
    static constexpr char KEY = 'A';
    static bool amI(char config)
    {
        return KEY == config;
    }
};

struct B {
    static constexpr char KEY = 'B';
    static bool amI(char config)
    {
        return KEY == config;
    }
};

struct C {
    static constexpr char KEY = 'C';
    static bool amI(char config)
    {
        return KEY == config;
    }
};

struct Base{
    virtual ~Base() = default;
    virtual void info() = 0;
};

template<typename First, typename Second>
struct Composite: public Base
{
    virtual void info()
    {
        std::cout<< First::KEY << Second::KEY << std::endl; 
    }
};


template<typename First, typename... Choices>
std::unique_ptr<Base> deduceSecond(std::string_view config)
{
    std::unique_ptr<Base> composite;
    ([&] {
        if(Choices::amI(config[1]))
        {   
            composite = std::make_unique<Composite<First, Choices>>();
            return true;
        }
        return false;
    }()
    || ...);
    return composite;
}

template<typename... Choices>
std::unique_ptr<Base> deduceFirst(std::string_view config)
{
    std::unique_ptr<Base> composite;
    ([&] {
        if(Choices::amI(config[0]))
        {   
            composite = std::move(deduceSecond<Choices, Choices...>(config));
            return true;
        }
        return false;
    }()
    || ...);
    return composite;
}

int main()
{
    std::unique_ptr<Base> compositeAC = deduceFirst<A, B, C>("AC");
    compositeAC->info();
    std::unique_ptr<Base> compositeBC = deduceFirst<A, B, C>("BC");
    compositeBC->info();
    return 0;
}