skills/compilers/cpp-templates/SKILL.md
C++ template skill for reading template errors and optimizing compile times. Use when deciphering template error stacks, setting -ftemplate-backtrace-limit, writing concepts and requires-clauses, understanding SFINAE vs concepts, or profiling template instantiation bottlenecks with Templight. Activates on queries about C++ templates, template error messages, concepts, requires expressions, SFINAE, template metaprogramming, or slow template compilation.
npx skillsauth add mohitmishra786/low-level-dev-skills cpp-templatesInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Guide agents through reading and fixing template error messages, using concepts as cleaner constraints, understanding SFINAE vs concepts trade-offs, and profiling template instantiation depth and compile times with Templight.
Template errors print full instantiation chains. Strategy: read from the bottom up.
prog.cpp:25:5: error: no matching function for call to 'sort'
std::sort(v.begin(), v.end());
^~~~~~~~~
/usr/include/c++/13/bits/stl_algo.h:4869:5: note: candidate:
template<class _RAIter>
void std::sort(_RAIter, _RAIter)
note: template argument deduction/substitution failed:
prog.cpp:25:5: note: 'MyType' is not a valid type for this template
^~~~~~~~
Rules for reading:
note: lines until you find "required from here" or "in instantiation of"# Limit backtrace depth to reduce noise
g++ -ftemplate-backtrace-limit=3 prog.cpp
clang -ftemplate-depth=32 prog.cpp # default 1024
# Show simplified errors (GCC 12+)
g++ -fconcepts-diagnostics-depth=3 prog.cpp # for concept failures
SFINAE (Substitution Failure Is Not An Error) silently removes overloads that fail substitution:
#include <type_traits>
// Enable function only for arithmetic types
template <typename T,
std::enable_if_t<std::is_arithmetic_v<T>, int> = 0>
T square(T x) { return x * x; }
// SFINAE with return type
template <typename T>
auto to_string(T x) -> std::enable_if_t<std::is_integral_v<T>, std::string> {
return std::to_string(x);
}
// Void-t technique for detecting member existence
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 {};
SFINAE errors are cryptic. Prefer concepts (C++20) for new code.
#include <concepts>
// Define a concept
template <typename T>
concept Arithmetic = std::is_arithmetic_v<T>;
template <typename T>
concept Printable = requires(T x) {
{ std::cout << x } -> std::same_as<std::ostream&>;
};
template <typename T>
concept Container = requires(T c) {
c.begin();
c.end();
c.size();
typename T::value_type;
};
// Apply concept as constraint
template <Arithmetic T>
T square(T x) { return x * x; }
// Abbreviated function template (C++20)
auto square(Arithmetic auto x) { return x * x; }
// requires-clause (more complex conditions)
template <typename T>
requires Arithmetic<T> && (sizeof(T) >= 4)
T big_square(T x) { return x * x; }
// Concept in auto parameter
void print_container(const Container auto& c) {
for (const auto& elem : c) std::cout << elem << ' ';
}
// requires { expression; } — checks expression is valid
// requires { expression -> type; } — checks type of expression
template <typename T>
concept HasPush = requires(T c, typename T::value_type v) {
c.push_back(v); // must be valid
{ c.front() } -> std::same_as<typename T::value_type&>; // type check
{ c.size() } -> std::convertible_to<std::size_t>; // convertible
requires std::default_initializable<T>; // nested requirement
};
// Compound requires (all must hold)
template <typename T>
concept Sortable = requires(T a, T b) {
{ a < b } -> std::convertible_to<bool>;
{ a == b } -> std::convertible_to<bool>;
};
| Aspect | SFINAE | Concepts |
|--------|--------|---------|
| Syntax | Complex, verbose | Clean, readable |
| Error messages | Cryptic wall-of-text | Clear constraint failure |
| Compile time | Can be slow (many substitutions) | Generally faster |
| C++ version | C++11 | C++20 |
| Short-circuit | No | Yes (concept subsumption) |
| Use in if constexpr | Awkward | Natural |
| Overload ranking | Manually via priority | Automatic by constraint specificity |
Migration: replace enable_if with concept constraints; replace void_t helpers with requires.
# Install Templight (Clang-based profiler)
# https://github.com/mikael-s-persson/templight
# Build with Templight tracing
clang++ -Xtemplight -profiler -Xtemplight -memory \
-std=c++17 prog.cpp -o prog
# Convert trace to visualizable format
templight-convert -f callgrind -o prof.out templight.pb
# View with KCachegrind
kcachegrind prof.out
# Find top template instantiation costs (without Templight)
# ClangBuildAnalyzer (easier)
ClangBuildAnalyzer --start /tmp/build
cmake --build build
ClangBuildAnalyzer --stop /tmp/build capture.bin
ClangBuildAnalyzer --analyze capture.bin | head -50
// 1. Explicit instantiation — compile once, use everywhere
// header.h
template <typename T>
T transform(T x);
extern template int transform<int>(int); // suppress instantiation
// impl.cpp
#include "header.h"
template int transform<int>(int); // instantiate here only
// 2. Prefer function templates over class templates when possible
// (functions instantiate lazily; class templates instantiate eagerly)
// 3. Use concepts to short-circuit failed substitutions
// (concept check is faster than full substitution failure)
// 4. Split heavy template headers from lightweight ones
// - Put type definitions in forward_decls.h
// - Put template implementations in impl.h (include only where needed)
// 5. Use if constexpr instead of specialization
template <typename T>
void process(T x) {
if constexpr (std::is_integral_v<T>) {
handle_int(x);
} else {
handle_other(x);
}
}
skills/build-systems/build-acceleration for ccache and PCH to reduce overall compile timeskills/compilers/clang for Clang-specific diagnostics and concept error outputskills/low-level-programming/cpp-coroutines for another advanced C++20 featuredevelopment
Zig testing skill for writing and running tests. Use when using zig build test, writing comptime tests, using test filters, working with test allocators to detect leaks, or using Zig's built-in fuzz testing (0.14+). Activates on queries about Zig tests, zig test, zig build test, comptime testing, test allocators, Zig fuzz testing, or detecting memory leaks in Zig tests.
development
Zig debugging skill. Use when debugging Zig programs with GDB or LLDB, interpreting Zig runtime panics, using std.debug.print for tracing, configuring debug builds, or debugging Zig programs in VS Code. Activates on queries about debugging Zig, Zig panics, zig gdb, zig lldb, std.debug.print, Zig stack traces, or Zig error return traces.
tools
Zig cross-compilation skill. Use when cross-compiling Zig programs to different targets, using Zig's built-in cross-compilation for embedded, WASM, Windows, ARM, or using zig cc to cross-compile C code without a system cross-toolchain. Activates on queries about Zig cross-compilation, zig target triples, zig cc cross-compile, Zig embedded targets, or Zig WASM.
development
Zig comptime skill for compile-time evaluation and metaprogramming. Use when using comptime parameters, comptime types, generics via anytype, comptime reflection with @typeInfo, or metaprogramming patterns that replace C++ templates. Activates on queries about Zig comptime, compile-time evaluation, Zig generics, anytype, @typeInfo, comptime types, or Zig metaprogramming.