mcpField
C
cpp-templates

cpp-templates

github.com/mohitmishra786开发269540 次安装18 周前更新
代码仓库

关于 cpp-templates

cpp-templates 是帮助 Agent 阅读和改进 C++ 模板代码的技能,适用于处理模板诊断、约束和编译耗时的开发者。内容涵盖 SFINAE、C++20 concepts、requires 表达式及 Templight 性能分析。

主要功能

  1. 01从实例化链定位模板错误
  2. 02使用 concepts 约束模板
  3. 03比较 SFINAE 与 concepts
  4. 04编写 requires 表达式
  5. 05使用 Templight 分析实例化耗时
  6. 06通过显式实例化减少编译时间

适用场景

  1. 01解读冗长的模板编译错误
  2. 02为模板重载添加类型约束
  3. 03将 SFINAE 代码迁移到 concepts
  4. 04定位模板实例化造成的编译耗时

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/mohitmishra786/low-level-dev-skills --skill cpp-templates

安装后在 Claude Code 中输入/cpp-templates确认已加载。

详细介绍

C++ 模板

用途

指导 Agent 阅读并修复模板错误消息、使用概念作为更简洁的约束、了解 SFINAE 与概念之间的取舍,以及使用 Templight 分析模板实例化深度和编译时间。

触发条件

  • “如何读懂这段冗长的 C++ 模板错误消息?”
  • “如何用概念约束模板?”
  • “SFINAE 和概念有什么区别?”
  • “我的模板导致编译非常慢”
  • “如何编写 requires 子句?”
  • “如何分析模板实例化时间?”

工作流

1. 阅读模板错误消息

模板错误会打印完整的实例化链。策略:从底部往上读。

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
                             ^~~~~~~~

阅读规则:

  1. 找到第一条错误行(输出顶部)——那就是你的代码
  2. 跳过所有 note: 行,直到找到 “required from here” 或 “in instantiation of”
  3. 调用栈底部会显示替换失败的类型
# 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
2. SFINAE——旧式约束技术

SFINAE(替换失败不是错误)会静默移除替换失败的重载:

#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 错误晦涩难懂。编写新代码时,优先使用概念(C++20)。

3. 概念——现代约束(C++20)
#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 << ' ';
}
4. Requires 表达式
// 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 与概念对比
方面SFINAE概念
语法复杂、冗长简洁、易读
错误消息晦涩冗长清晰指出约束失败
编译时间可能很慢(需要多次替换)通常更快
C++ 版本C++11C++20
短路求值否是(概念包含关系)
在 if constexpr 中使用不方便自然
重载排序通过优先级手动控制根据约束的特定性自动确定

迁移方式:用概念约束替换 enable_if;用 requires 替换 void_t 辅助项。

6. 使用 Templight 分析模板实例化
# 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
7. 缩短模板编译时间
// 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,通过 ccache 和 PCH 缩短整体编译时间
  • 使用 skills/compilers/clang,了解 Clang 专属诊断和概念错误输出
  • 使用 skills/low-level-programming/cpp-coroutines,了解另一项高级 C++20 特性

评论

支持 Markdown