Cpp Templates

mohitmishra786/low-level-dev-skills/skills/compilers/cpp-templates

作者 mohitmishra786bdc58472fa9f無授權條款253 個星標收錄於 2026年10月9日更新於 2026年10月9日儲存庫3 個月前更新

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.

AI 產生的概覽

引導代理閱讀 C++ 樣板錯誤、撰寫 concepts 與 requires 子句,並分析樣板編譯時間。

功能
此技能提供診斷與修正 C++ 樣板問題的說明。內容涵蓋閱讀樣板具現化錯誤堆疊、使用 SFINAE 與 C++20 concepts 及 requires 運算式、比較兩種做法,以及用 Templight 或 ClangBuildAnalyzer 分析樣板具現化。它也列出縮短樣板編譯時間的技巧,例如明確具現化與 if constexpr。
適用情境
適用於解讀冗長的 C++ 樣板錯誤訊息、以 concepts 或 requires 子句約束樣板、在 SFINAE 與 concepts 之間取捨,或排查樣板編譯緩慢與具現化深度的問題。
執行需求
不含指令碼,僅為說明性內容。依其指引操作需要 C++ 工具鏈(例如 GCC 或 Clang),效能分析部分另提及須自行安裝的選用外部工具(Templight、templight-convert、KCachegrind、ClangBuildAnalyzer)。

C++ Templates

Purpose

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.

Triggers

  • "How do I read this massive C++ template error?"
  • "How do I use concepts to constrain a template?"
  • "What's the difference between SFINAE and concepts?"
  • "My templates make compilation very slow"
  • "How do I write a requires-clause?"
  • "How do I profile template instantiation times?"

Workflow

1. Reading template error messages

Template errors print full instantiation chains. Strategy: read from the bottom up.

text
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:

  1. Find the first error line (top of output) — that's your code
  2. Skip all the note: lines until you find "required from here" or "in instantiation of"
  3. The bottom of the stack shows the type that failed substitution
bash
# Limit backtrace depth to reduce noiseg++   -ftemplate-backtrace-limit=3  prog.cppclang -ftemplate-depth=32           prog.cpp   # default 1024
# Show simplified errors (GCC 12+)g++ -fconcepts-diagnostics-depth=3  prog.cpp   # for concept failures

2. SFINAE — legacy constraint technique

SFINAE (Substitution Failure Is Not An Error) silently removes overloads that fail substitution:

cpp
#include <type_traits>
// Enable function only for arithmetic typestemplate <typename T,    std::enable_if_t<std::is_arithmetic_v<T>, int> = 0>T square(T x) { return x * x; }
// SFINAE with return typetemplate <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 existencetemplate <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.

3. Concepts — modern constraints (C++20)

cpp
#include <concepts>
// Define a concepttemplate <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 constrainttemplate <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 parametervoid print_container(const Container auto& c) {    for (const auto& elem : c) std::cout << elem << ' ';}

4. Requires expressions

cpp
// 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>;};

5. SFINAE vs concepts comparison

AspectSFINAEConcepts
SyntaxComplex, verboseClean, readable
Error messagesCryptic wall-of-textClear constraint failure
Compile timeCan be slow (many substitutions)Generally faster
C++ versionC++11C++20
Short-circuitNoYes (concept subsumption)
Use in if constexprAwkwardNatural
Overload rankingManually via priorityAutomatic by constraint specificity

Migration: replace enable_if with concept constraints; replace void_t helpers with requires.

6. Template instantiation profiling with Templight

bash
# Install Templight (Clang-based profiler)# https://github.com/mikael-s-persson/templight
# Build with Templight tracingclang++ -Xtemplight -profiler -Xtemplight -memory \        -std=c++17 prog.cpp -o prog
# Convert trace to visualizable formattemplight-convert -f callgrind -o prof.out templight.pb
# View with KCachegrindkcachegrind prof.out
# Find top template instantiation costs (without Templight)# ClangBuildAnalyzer (easier)ClangBuildAnalyzer --start /tmp/buildcmake --build buildClangBuildAnalyzer --stop /tmp/build capture.binClangBuildAnalyzer --analyze capture.bin | head -50

7. Reducing template compile times

cpp
// 1. Explicit instantiation — compile once, use everywhere// header.htemplate <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 specializationtemplate <typename T>void process(T x) {    if constexpr (std::is_integral_v<T>) {        handle_int(x);    } else {        handle_other(x);    }}

Related skills

  • Use skills/build-systems/build-acceleration for ccache and PCH to reduce overall compile time
  • Use skills/compilers/clang for Clang-specific diagnostics and concept error output
  • Use skills/low-level-programming/cpp-coroutines for another advanced C++20 feature

來源與署名

來源:mohitmishra786/low-level-dev-skills位於skills/compilers/cpp-templates提交bdc5847

授權條款: 無授權條款

內容歸原作者所有。SourceWeft 從公開儲存庫中收錄這些內容。

檢舉或申請下架