concepts(C++20 约束)演示
同一套"仅接受整数类型"的约束,用 C++11 SFINAE 与 C++20 concepts 各写一遍,对比错误信息、体积与编译成本。
文件
| 文件 | 作用 | 编译 |
|---|---|---|
sfinae.cpp | C++11 SFINAE 约束实现(enable_if 返回类型 + 默认模板参数两种写法) | g++ -std=c++11 |
concepts.cpp | C++20 concepts 等价实现(requires 子句 + 约束模板参数两种写法),含 static_assert 谓词演示 | g++ -std=c++20(需 GCC 10+) |
err-sfinae.cpp | 单候选 SFINAE 约束失败:传 double | 预期编译失败 |
err-concepts.cpp | 单候选 concepts 约束失败:传 double | 预期编译失败 |
err2-sfinae.cpp | 多候选 SFINAE 全失败:传 std::string | 预期编译失败 |
err2-concepts.cpp | 多候选 concepts 全失败:与 SFINAE 同场景 | 预期编译失败 |
构建与运行
bash
make run # 编译并运行两种实现,输出一致:42 / 4
make errors # 四组约束失败错误信息对比(错误行数 + 关键内容)
make size # 同编译器(GCC 10)下二进制体积与编译耗时服务器实测环境:CentOS 7 + 系统 g++ 4.8.5 + devtoolset-10(GCC 10.2.1,/opt/rh/devtoolset-10/root/usr/bin/g++)。
实测数据(2026-08-27,服务器)
运行输出(两种实现语义一致)
SFINAE 版: 42 / 4
concepts 版:42 / 4约束失败错误信息
| 场景 | 编译命令 | 错误行数 | 关键错误 |
|---|---|---|---|
| 单候选 SFINAE | g++ 4.8 -std=c++11 | 12 | no type named 'type' in 'struct std::enable_if<false, double>' |
| 单候选 concepts | g++ 10 -std=c++20 | 15 | use of function ... with unsatisfied constraints / evaluated to 'false' |
| 多候选 SFINAE | g++ 10 -std=c++11 | 25 | no matching function + 每个候选的替换失败细节 |
| 多候选 concepts | g++ 10 -std=c++20 | 36 | 每个候选 constraints not satisfied + evaluated to 'false' |
行数不是全部:SFINAE 的错误描述的是模板内部细节(enable_if<false, double> 里没有 type),需要读者自己反向推断"哦,原来是不满足整型约束";concepts 的错误直接点名约束(constraints not satisfied、is_integral_v<_Tp> evaluated to 'false'),错误定位在源码行,可读性完全不同。
体积与编译耗时(同编译器 GCC 10,公平对照)
| 指标 | SFINAE(C++11) | concepts(C++20) |
|---|---|---|
| 二进制体积(-g) | 34208 B | 34040 B |
| 编译耗时(3 次取最小) | 0.19 s | 0.40 s |
体积几乎相同(运行期零开销)。编译耗时差异主要来自 C++20 标准库 <concepts> 头文件本身更大,与概念机制无关——若用手写 concept 替换标准库头,两者基本打平。
复现
- 服务器安装 devtoolset-10(或本机 GCC 10+):
sudo yum install -y --nogpgcheck devtoolset-10-gcc-c++ bash run-remote.sh一键复现全部数据。