Claude
Skills
Sign in
Back

cpp-templates-metaprogramming

Included with Lifetime
$97 forever

Use when C++ templates and metaprogramming including template specialization, SFINAE, type traits, and C++20 concepts.

General

What this skill does


# C++ Templates and Metaprogramming

Template metaprogramming enables compile-time computation and code generation,
creating flexible, efficient abstractions without runtime overhead. This skill
covers function and class templates, specialization, SFINAE, type traits, and
modern concepts-based template constraints.

## Function Templates

Function templates enable writing generic algorithms that work with any type
satisfying requirements.

```cpp
#include <iostream>
#include <vector>
#include <string>

// Basic function template
template<typename T>
T maximum(T a, T b) {
    return (a > b) ? a : b;
}

// Multiple template parameters
template<typename T, typename U>
auto add(T a, U b) -> decltype(a + b) {
    return a + b;
}

// Template with non-type parameters
template<typename T, size_t N>
size_t array_size(T (&)[N]) {
    return N;
}

// Template overloading
template<typename T>
void print(T value) {
    std::cout << value << "\n";
}

template<typename T>
void print(const std::vector<T>& vec) {
    for (const auto& item : vec) {
        std::cout << item << " ";
    }
    std::cout << "\n";
}

void function_template_examples() {
    auto max_int = maximum(10, 20);
    auto max_double = maximum(3.14, 2.71);
    auto max_string = maximum(std::string("abc"), std::string("xyz"));

    auto sum = add(5, 3.14);  // int + double

    int arr[] = {1, 2, 3, 4, 5};
    std::cout << "Array size: " << array_size(arr) << "\n";

    print(42);
    print(std::vector<int>{1, 2, 3});
}
```

## Class Templates

Class templates enable creating generic containers and data structures.

```cpp
#include <iostream>
#include <stdexcept>

// Basic class template
template<typename T>
class Stack {
    T* data_;
    size_t size_;
    size_t capacity_;

public:
    Stack(size_t capacity = 10)
        : data_(new T[capacity])
        , size_(0)
        , capacity_(capacity) {}

    ~Stack() {
        delete[] data_;
    }

    void push(const T& value) {
        if (size_ >= capacity_) {
            resize();
        }
        data_[size_++] = value;
    }

    T pop() {
        if (size_ == 0) {
            throw std::underflow_error("Stack is empty");
        }
        return data_[--size_];
    }

    bool empty() const { return size_ == 0; }
    size_t size() const { return size_; }

private:
    void resize() {
        capacity_ *= 2;
        T* new_data = new T[capacity_];
        for (size_t i = 0; i < size_; ++i) {
            new_data[i] = data_[i];
        }
        delete[] data_;
        data_ = new_data;
    }
};

// Multiple template parameters
template<typename Key, typename Value>
class Pair {
    Key key_;
    Value value_;

public:
    Pair(const Key& k, const Value& v) : key_(k), value_(v) {}

    const Key& key() const { return key_; }
    const Value& value() const { return value_; }
};

// Template with default parameters
template<typename T, typename Allocator = std::allocator<T>>
class Vector {
    // Implementation
};

void class_template_examples() {
    Stack<int> int_stack;
    int_stack.push(1);
    int_stack.push(2);
    std::cout << int_stack.pop() << "\n";

    Stack<std::string> str_stack;
    str_stack.push("hello");

    Pair<std::string, int> p("age", 30);
}
```

## Template Specialization

Template specialization allows providing custom implementations for specific
types.

```cpp
#include <iostream>
#include <cstring>

// Primary template
template<typename T>
class Container {
    T value_;

public:
    Container(const T& value) : value_(value) {}

    void print() const {
        std::cout << "Generic: " << value_ << "\n";
    }

    size_t memory_size() const {
        return sizeof(T);
    }
};

// Full specialization for const char*
template<>
class Container<const char*> {
    const char* value_;

public:
    Container(const char* value) : value_(value) {}

    void print() const {
        std::cout << "C-string: " << value_ << "\n";
    }

    size_t memory_size() const {
        return std::strlen(value_) + 1;
    }
};

// Partial specialization for pointers
template<typename T>
class Container<T*> {
    T* value_;

public:
    Container(T* value) : value_(value) {}

    void print() const {
        std::cout << "Pointer: " << *value_ << "\n";
    }

    size_t memory_size() const {
        return sizeof(T*);
    }
};

// Function template specialization
template<typename T>
bool is_negative(T value) {
    return value < 0;
}

template<>
bool is_negative<bool>(bool value) {
    return false;  // bool can't be negative
}

void specialization_examples() {
    Container<int> c1(42);
    c1.print();  // Generic

    Container<const char*> c2("hello");
    c2.print();  // C-string

    int x = 10;
    Container<int*> c3(&x);
    c3.print();  // Pointer
}
```

## SFINAE (Substitution Failure Is Not An Error)

SFINAE enables compile-time function selection based on type properties.

```cpp
#include <iostream>
#include <type_traits>
#include <vector>

// Enable if type has begin() and end()
template<typename T>
typename std::enable_if<
    std::is_same<
        decltype(std::declval<T>().begin()),
        decltype(std::declval<T>().end())
    >::value
>::type print_container(const T& container) {
    std::cout << "Container: ";
    for (const auto& item : container) {
        std::cout << item << " ";
    }
    std::cout << "\n";
}

// Enable if type is arithmetic
template<typename T>
typename std::enable_if<std::is_arithmetic<T>::value>::type
print_value(T value) {
    std::cout << "Number: " << value << "\n";
}

// Enable if type is not arithmetic
template<typename T>
typename std::enable_if<!std::is_arithmetic<T>::value>::type
print_value(const T& value) {
    std::cout << "Non-number: " << value << "\n";
}

// Using std::enable_if as template parameter
template<typename T,
         typename = std::enable_if_t<std::is_integral<T>::value>>
T safe_divide(T a, T b) {
    if (b == 0) {
        throw std::domain_error("Division by zero");
    }
    return a / b;
}

// Tag dispatching (alternative to SFINAE)
template<typename T>
void process_impl(T value, std::true_type /* is_pointer */) {
    std::cout << "Processing pointer: " << *value << "\n";
}

template<typename T>
void process_impl(T value, std::false_type /* is_pointer */) {
    std::cout << "Processing value: " << value << "\n";
}

template<typename T>
void process(T value) {
    process_impl(value, std::is_pointer<T>{});
}

void sfinae_examples() {
    std::vector<int> vec{1, 2, 3};
    print_container(vec);

    print_value(42);
    print_value(std::string("hello"));

    std::cout << safe_divide(10, 2) << "\n";

    int x = 100;
    process(x);
    process(&x);
}
```

## Type Traits

Type traits provide compile-time type information and transformations.

```cpp
#include <type_traits>
#include <iostream>
#include <string>

// Using standard type traits
template<typename T>
void analyze_type() {
    std::cout << "Type analysis:\n";
    std::cout << "  Is integral: "
              << std::is_integral<T>::value << "\n";
    std::cout << "  Is floating point: "
              << std::is_floating_point<T>::value << "\n";
    std::cout << "  Is pointer: "
              << std::is_pointer<T>::value << "\n";
    std::cout << "  Is const: "
              << std::is_const<T>::value << "\n";
    std::cout << "  Size: " << sizeof(T) << "\n";
}

// Type transformations
template<typename T>
void transform_type() {
    using NoCV = std::remove_cv_t<T>;
    using NoRef = std::remove_reference_t<T>;
    using NoPtr = std::remove_pointer_t<T>;
    using AddConst = std::add_const_t<T>;
    using AddLRef = std::add_lvalue_reference_t<T>;

    std::cout << "Is same after remove_cv: "
              << std::is_same<NoCV, T>::value << "\n";
}

// Custom type trait
template<typename T>
struct is_string : std::false_type {};

template<>
struct is_string<std::string> : std::true_type {};

template<>
struct is_string<const char*> : std::true_type {};

template<typename T>
inline constexpr bool is_string_v = i

Related in General