本文解析ghc::filesystem的一段模板代码,涉及模板特化/偏特化的参数也需要模板参数的情形,以及std::enable_if的使用。
C++特化模板的内部匹配参数代码解析
代码背景
1 | template <class T> |
这段代码来自ghc::filesystem
该代码实现了:
_is_basic_string
:判断类型是否为std::basic_string
(如std::string
/std::wstring
)startsWith
/endsWith
:模板函数,仅在参数类型是字符串时可用
问题及解析
_is_basic_string<strT>::value
来自哪里?
_is_basic_string
是自定义模板类,继承自std::true_type
/std::false_type
std::true_type
/std::false_type
定义了static constexpr bool value
_is_basic_string<strT>::value
实际上就是访问该静态布尔值
_is_basic_string
是一个模板参数,还是三个?
_is_basic_string
是一个 模板类,只有一个模板参数T
特化模板:
1
2template <class CharT, class Traits, class Alloc>
struct _is_basic_string<std::basic_string<CharT, Traits, Alloc>> : std::true_type {};- 这里的三个参数是用于匹配 T 内部结构,不是外层模板参数;这里模板偏特化,属于模板特化/偏特化
- 外层模板参数仍然只有一个:
T
可以继续对三个模板参数特化吗?
✅ 可以通过 部分特化 对
CharT
/Traits
/Alloc
进行细分例:
1
2template <class Traits, class Alloc>
struct _is_basic_string<std::basic_string<char, Traits, Alloc>> : std::true_type {};❌ 不能直接“嵌套特化”内部三个参数,只能通过外层模板写新的部分特化
4.
typename std::enable_if<...>::type = true
怎么写的?
std::enable_if<condition, bool>::type
:如果condition
为 true,则 type = bool,否则不存在= true
是默认值,允许模板参数自动推导SFINAE 逻辑:
- 条件为 true → 模板启用
- 条件为 false → 替换失败,模板被忽略
5. 默认值是必须的吗?
❌ 不必须
✅ 推荐保留,使模板参数可自动推导
不写默认值时,需要调用时显式指定第二模板参数
例:
1
startsWith<std::string, true>(...); // 这样才行,但很丑
6. = false
可行吗?
- ✅ 可以
- 功能与
= true
一样,SFINAE 逻辑不受影响 - 仅影响模板参数默认值(签名上为
false
),可读性稍差
7.
typename = typename std::enable_if<...>::type
是否可行?
1
2
3
4
5
6
7template <bool _Test, class _Ty = void>
struct enable_if {};
template <
typename strT,
typename = typename std::enable_if<path::_is_basic_string<strT>::value>::type
>
✅ 可以
不需要默认值
简化写法,更现代、更可读
不指定 enable_if 的第二个模板参数(默认为 void)
直接用一个无名模板参数 typename = …
当条件不满足时,std::enable_if
::type 不存在 → SFINAE 触发 当条件满足时,std::enable_if
::type 为 void,模板启用 C++14 可进一步简化为:
1
template <typename strT, typename = std::enable_if_t<path::_is_basic_string<strT>::value>>
总结表格
问题 | 解析 |
---|---|
_is_basic_string<strT>::value 来源 |
来自 _is_basic_string 模板,继承
std::true_type / std::false_type 的
value |
_is_basic_string 模板参数数目 |
外层只有 1 个模板参数 T;特化内部有三个用于匹配字符串类型 |
是否可对三个模板参数再特化 | ✅ 可通过部分特化针对内部参数组合 |
typename std::enable_if<...>::type = true
作用 |
SFINAE 控制函数模板是否启用;= true
提供默认值便于自动推导 |
默认值是否必须 | ❌ 不必须,但推荐保留以便调用时不用显式写模板参数 |
默认值是否可以 = false |
✅ 可行,功能不变,仅影响默认签名值 |
是否可以用
typename = typename std::enable_if<...>::type |
✅ 完全可行,更简洁,不需要默认值 |
C++14 推荐写法 | typename = std::enable_if_t<condition> |
示例:现代写法
1 | template <typename strT, typename = std::enable_if_t<_is_basic_string<strT>::value>> |