Production-grade skill for C++ template programming and metaprogramming. Covers function/class templates, variadic templates, SFINAE, concepts, type traits, and compile-time computation.
Provides C++ template metaprogramming expertise from basic templates to advanced concepts. Use when users need variadic templates, SFINAE, concepts, type traits, or compile-time computation.
/plugin marketplace add pluginagentmarketplace/custom-plugin-cpp/plugin install cpp@pluginagentmarketplace-cppThis skill inherits all available tools. When active, it can use any tool Claude has access to.
assets/config.yamlassets/schema.jsonreferences/GUIDE.mdreferences/PATTERNS.mdscripts/validate.pyProduction-Grade Development Skill | C++ Template Metaprogramming
Master C++ template programming from basics to advanced metaprogramming techniques.
// Basic function template
template<typename T>
T max(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;
}
// C++20: Abbreviated function template
auto multiply(auto a, auto b) {
return a * b;
}
// Non-type template parameter
template<typename T, std::size_t N>
constexpr std::size_t array_size(T (&)[N]) {
return N;
}
// Template argument deduction
max(1, 2); // T = int
max(1.0, 2.0); // T = double
max<double>(1, 2); // Explicit: T = double
template<typename T, std::size_t Capacity = 64>
class FixedVector {
std::array<T, Capacity> data_;
std::size_t size_ = 0;
public:
void push_back(const T& value) {
if (size_ < Capacity) {
data_[size_++] = value;
}
}
T& operator[](std::size_t idx) { return data_[idx]; }
const T& operator[](std::size_t idx) const { return data_[idx]; }
std::size_t size() const { return size_; }
static constexpr std::size_t capacity() { return Capacity; }
};
// Class Template Argument Deduction (CTAD) - C++17
FixedVector vec{1, 2, 3}; // Deduces FixedVector<int, 3>
// Deduction guide
template<typename T, typename... Args>
FixedVector(T, Args...) -> FixedVector<T, 1 + sizeof...(Args)>;
// Primary template
template<typename T>
struct TypeInfo {
static constexpr const char* name = "unknown";
};
// Full specialization
template<>
struct TypeInfo<int> {
static constexpr const char* name = "int";
};
template<>
struct TypeInfo<double> {
static constexpr const char* name = "double";
};
// Partial specialization
template<typename T>
struct TypeInfo<std::vector<T>> {
static constexpr const char* name = "vector";
using element_type = T;
};
// Partial specialization for pointers
template<typename T>
struct TypeInfo<T*> {
static constexpr const char* name = "pointer";
using pointed_type = T;
};
// Variadic function template
template<typename... Args>
void print(Args... args) {
((std::cout << args << ' '), ...); // Fold expression (C++17)
std::cout << '\n';
}
// Sizeof... operator
template<typename... Args>
constexpr std::size_t count_args() {
return sizeof...(Args);
}
// Recursive unpacking (pre-C++17)
template<typename T>
void print_recursive(T t) {
std::cout << t << '\n';
}
template<typename T, typename... Rest>
void print_recursive(T first, Rest... rest) {
std::cout << first << ' ';
print_recursive(rest...);
}
// Unary right fold: (pack op ...)
template<typename... Args>
auto sum(Args... args) {
return (args + ...); // ((a + b) + c) + d...
}
// Unary left fold: (... op pack)
template<typename... Args>
auto sum_left(Args... args) {
return (... + args); // a + (b + (c + d...))
}
// Binary fold with init
template<typename... Args>
auto sum_with_init(Args... args) {
return (0 + ... + args); // 0 + a + b + c...
}
// Logical folds
template<typename... Args>
bool all(Args... args) {
return (... && args); // All true
}
template<typename... Args>
bool any(Args... args) {
return (... || args); // Any true
}
// Comma fold for side effects
template<typename F, typename... Args>
void for_each_arg(F f, Args&&... args) {
(f(std::forward<Args>(args)), ...);
}
#include <type_traits>
// Enable only for integral types
template<typename T>
typename std::enable_if<std::is_integral<T>::value, T>::type
safe_divide(T a, T b) {
return b != 0 ? a / b : 0;
}
// C++14 style
template<typename T>
std::enable_if_t<std::is_floating_point_v<T>, T>
safe_divide(T a, T b) {
return b != T{0} ? a / b : std::numeric_limits<T>::quiet_NaN();
}
// Using void_t for detection idiom
template<typename, typename = void>
struct has_size : std::false_type {};
template<typename T>
struct has_size<T, std::void_t<decltype(std::declval<T>().size())>>
: std::true_type {};
// Usage
static_assert(has_size<std::vector<int>>::value);
static_assert(!has_size<int>::value);
// is_detected implementation
template<typename, template<typename...> class, typename...>
struct is_detected_impl : std::false_type {};
template<template<typename...> class Op, typename... Args>
struct is_detected_impl<std::void_t<Op<Args...>>, Op, Args...>
: std::true_type {};
template<template<typename...> class Op, typename... Args>
using is_detected = is_detected_impl<void, Op, Args...>;
// Detection expressions
template<typename T>
using has_begin_t = decltype(std::declval<T>().begin());
template<typename T>
using has_end_t = decltype(std::declval<T>().end());
template<typename T>
constexpr bool is_container_v =
is_detected<has_begin_t, T>::value &&
is_detected<has_end_t, T>::value;
#include <concepts>
// Using standard concepts
template<std::integral T>
T gcd(T a, T b) {
while (b != 0) {
T t = b;
b = a % b;
a = t;
}
return a;
}
// Common standard concepts
template<std::floating_point T>
T sqrt_approx(T x);
template<std::copyable T>
void process(T value);
template<std::invocable<int> F>
void apply(F&& func);
template<std::ranges::range R>
void iterate(R&& range);
// Define concept with requires expression
template<typename T>
concept Hashable = requires(T a) {
{ std::hash<T>{}(a) } -> std::convertible_to<std::size_t>;
};
template<typename T>
concept Printable = requires(std::ostream& os, T value) {
{ os << value } -> std::same_as<std::ostream&>;
};
template<typename T>
concept Container = requires(T c) {
typename T::value_type;
typename T::iterator;
{ c.begin() } -> std::same_as<typename T::iterator>;
{ c.end() } -> std::same_as<typename T::iterator>;
{ c.size() } -> std::convertible_to<std::size_t>;
};
// Compound concepts
template<typename T>
concept Numeric = std::integral<T> || std::floating_point<T>;
// Use in function
template<Container C>
void process(const C& container) {
for (const auto& item : container) {
// ...
}
}
// Constrained auto
void print_hashable(Hashable auto const& value) {
std::cout << std::hash<std::decay_t<decltype(value)>>{}(value);
}
// Requires clause in template
template<typename T>
requires std::is_arithmetic_v<T>
T average(std::span<const T> values) {
return std::reduce(values.begin(), values.end()) / values.size();
}
// Trailing requires
template<typename T>
T* find(T* first, T* last, const T& value)
requires std::equality_comparable<T>
{
while (first != last && *first != value) {
++first;
}
return first;
}
// Concept subsumption for overloading
template<typename T>
void process(T val) requires std::integral<T> {
std::cout << "integral\n";
}
template<typename T>
void process(T val) requires std::signed_integral<T> { // More specific
std::cout << "signed integral\n";
}
#include <type_traits>
// Type categories
static_assert(std::is_integral_v<int>);
static_assert(std::is_floating_point_v<double>);
static_assert(std::is_class_v<std::string>);
static_assert(std::is_pointer_v<int*>);
// Type properties
static_assert(std::is_const_v<const int>);
static_assert(std::is_trivially_copyable_v<int>);
static_assert(std::is_default_constructible_v<std::string>);
// Type transformations
using NoConst = std::remove_const_t<const int>; // int
using Pointer = std::add_pointer_t<int>; // int*
using Decayed = std::decay_t<int&>; // int
using Common = std::common_type_t<int, double>; // double
// Conditional type
template<typename T>
using storage_type = std::conditional_t<
sizeof(T) <= sizeof(void*),
T, // Small: store by value
std::unique_ptr<T> // Large: store by pointer
>;
// Custom type trait
template<typename T>
struct is_smart_pointer : std::false_type {};
template<typename T>
struct is_smart_pointer<std::unique_ptr<T>> : std::true_type {};
template<typename T>
struct is_smart_pointer<std::shared_ptr<T>> : std::true_type {};
template<typename T>
constexpr bool is_smart_pointer_v = is_smart_pointer<T>::value;
// Type transformation
template<typename T>
struct remove_all_pointers {
using type = T;
};
template<typename T>
struct remove_all_pointers<T*> {
using type = typename remove_all_pointers<T>::type;
};
template<typename T>
using remove_all_pointers_t = typename remove_all_pointers<T>::type;
// Usage
static_assert(std::is_same_v<remove_all_pointers_t<int***>, int>);
// Compile-time factorial
constexpr int factorial(int n) {
return n <= 1 ? 1 : n * factorial(n - 1);
}
static_assert(factorial(5) == 120);
// constexpr class
class ConstexprString {
const char* data_;
std::size_t size_;
public:
constexpr ConstexprString(const char* str)
: data_(str), size_(0) {
while (str[size_] != '\0') ++size_;
}
constexpr std::size_t size() const { return size_; }
constexpr char operator[](std::size_t i) const { return data_[i]; }
};
constexpr auto hello = ConstexprString("Hello");
static_assert(hello.size() == 5);
// Guaranteed compile-time evaluation
consteval int square(int n) {
return n * n;
}
constexpr int x = square(5); // OK: compile-time
// int y = square(runtime_value); // Error: must be compile-time
// Compile-time string hashing
consteval std::size_t hash_string(std::string_view str) {
std::size_t hash = 0;
for (char c : str) {
hash = hash * 31 + static_cast<std::size_t>(c);
}
return hash;
}
// Use in switch
switch (hash_string(input)) {
case hash_string("foo"): /* ... */ break;
case hash_string("bar"): /* ... */ break;
}
// Without concepts - cryptic error
template<typename T>
void sort_container(T& container) {
std::sort(container.begin(), container.end());
}
// Error with int: no member named 'begin' in 'int'
// With concepts - clear error
template<typename T>
concept Sortable = requires(T c) {
{ c.begin() } -> std::random_access_iterator;
{ c.end() } -> std::random_access_iterator;
};
template<Sortable T>
void sort_container(T& container) {
std::sort(container.begin(), container.end());
}
// Error with int: constraints not satisfied [Sortable]
template<typename T>
class NumericContainer {
static_assert(std::is_arithmetic_v<T>,
"NumericContainer requires an arithmetic type (int, float, etc.)");
// ...
};
// Clear error:
// error: static assertion failed: NumericContainer requires an arithmetic type
Template error?
├── "no matching function"
│ ├── Check template parameter deduction
│ ├── Check SFINAE conditions
│ └── Add explicit template arguments
├── "ambiguous call"
│ ├── Make one overload more specific
│ ├── Use concepts for disambiguation
│ └── Add explicit template arguments
├── "incomplete type"
│ ├── Forward declare issue
│ ├── Move implementation to .cpp (explicit instantiation)
│ └── Check circular dependencies
├── "exceeds maximum depth"
│ ├── Add base case to recursion
│ ├── Increase compiler limit
│ └── Use fold expressions instead
└── "constraint not satisfied"
├── Check concept requirements
└── Add missing operations to type
#include <gtest/gtest.h>
#include <type_traits>
class TemplateTest : public ::testing::Test {};
// Test type traits
TEST_F(TemplateTest, TypeTraitsWork) {
static_assert(std::is_integral_v<int>);
static_assert(!std::is_integral_v<double>);
static_assert(is_smart_pointer_v<std::unique_ptr<int>>);
}
// Test concepts
TEST_F(TemplateTest, ConceptsSatisfied) {
static_assert(Hashable<int>);
static_assert(Hashable<std::string>);
static_assert(Container<std::vector<int>>);
static_assert(!Container<int>);
}
// Test variadic templates
TEST_F(TemplateTest, VariadicSum) {
EXPECT_EQ(sum(1, 2, 3, 4, 5), 15);
EXPECT_DOUBLE_EQ(sum(1.0, 2.5, 3.5), 7.0);
}
// Test constexpr
TEST_F(TemplateTest, ConstexprComputation) {
constexpr auto result = factorial(5);
EXPECT_EQ(result, 120);
constexpr auto hash = hash_string("test");
EXPECT_NE(hash, 0);
}
// Test template specialization
TEST_F(TemplateTest, Specialization) {
EXPECT_STREQ(TypeInfo<int>::name, "int");
EXPECT_STREQ(TypeInfo<double>::name, "double");
EXPECT_STREQ(TypeInfo<std::vector<int>>::name, "vector");
}
| Component | Interface |
|---|---|
stl-master | Generic containers |
modern-cpp-expert | Concepts, constexpr |
performance-optimizer | Compile-time optimization |
cpp-algorithms-agent | Generic algorithms |
C++ Plugin v3.0.0 - Production-Grade Development Skill
This skill should be used when the user asks to "create a slash command", "add a command", "write a custom command", "define command arguments", "use command frontmatter", "organize commands", "create command with file references", "interactive command", "use AskUserQuestion in command", or needs guidance on slash command structure, YAML frontmatter fields, dynamic arguments, bash execution in commands, user interaction patterns, or command development best practices for Claude Code.
This skill should be used when the user asks to "create an agent", "add an agent", "write a subagent", "agent frontmatter", "when to use description", "agent examples", "agent tools", "agent colors", "autonomous agent", or needs guidance on agent structure, system prompts, triggering conditions, or agent development best practices for Claude Code plugins.
This skill should be used when the user asks to "create a hook", "add a PreToolUse/PostToolUse/Stop hook", "validate tool use", "implement prompt-based hooks", "use ${CLAUDE_PLUGIN_ROOT}", "set up event-driven automation", "block dangerous commands", or mentions hook events (PreToolUse, PostToolUse, Stop, SubagentStop, SessionStart, SessionEnd, UserPromptSubmit, PreCompact, Notification). Provides comprehensive guidance for creating and implementing Claude Code plugin hooks with focus on advanced prompt-based hooks API.