考虑以下代码片段(C++20、gcc、clang):
template <class>
struct wrapper;
template <int>
struct backend{};
//(1) OK
template <int Arg>
using my_type = backend<Arg>;
//(2) Doesn't compile
//template <int Arg>
//using my_type = backend<Arg + 1>;
//(3) OK
//template <int Arg>
//struct my_type : backend<Arg + 1>{};
template <int Arg>
struct wrapper<my_type<Arg>> {};
int main() {
[[maybe_unused]] wrapper<my_type<1>> w;
}
为什么 (2) 不能编译而 (3) 可以编译?
Clang 错误:prog.cc:20:12:错误:类模板部分 特化包含无法推导的模板参数; 这种部分专业化永远不会被使用 [-Wunusable-部分专业化] 20 |结构体 包装器
{};
如果您能参考该标准,我将不胜感激。
匹配部分特化依赖于模板参数推导,而别名模板永远不会被推导。
参见 [temp.alias/2]:
当 template-id 引用别名模板的特化时,它相当于用其 template-argument 替换别名模板的定义类型 id 中的模板参数而获得的关联类型。
[注1: 永远不会推导出别名模板名称。 — 尾注]
示例1(OK):
template <class>
struct wrapper;
template <int>
struct backend{};
template <int Arg>
using my_type = backend<Arg>;
template <int Arg>
struct wrapper<my_type<Arg>> {};
// --> equivalent to:
// struct wrapper<backend<Arg>>
int main() {
[[maybe_unused]] wrapper<my_type<1>> w;
// --> equivalent to:
// [[maybe_unused]] wrapper<backend<1>> w;
}
演绎将
wrapper<backend<1>>
与 wrapper<backend<Arg>>
进行比较。在此推导的背景下,Arg
可推导为 1
。
示例 2(不好):
template <class>
struct wrapper;
template <int Arg>
using my_type = backend<Arg + 1>;
template <int Arg>
struct wrapper<my_type<Arg>> {};
// --> equivalent to:
// struct wrapper<backend<Arg + 1>>
int main() {
[[maybe_unused]] wrapper<my_type<1>> w;
// --> equivalent to:
// [[maybe_unused]] wrapper<backend<2>> w;
}
演绎将
wrapper<backend<2>>
与 wrapper<backend<Arg + 1>>
进行比较。在此推论的背景下,Arg
不可推导。
这是因为 [temp.deduct.type/5.4]:
(非推导上下文包括:)非类型模板参数或其中子表达式引用模板参数的数组边界。
示例3(OK):
template <class>
struct wrapper;
template <int>
struct backend{};
template <int Arg>
struct my_type : backend<Arg + 1>{};
template <int Arg>
struct wrapper<my_type<Arg>> {};
int main() {
[[maybe_unused]] wrapper<my_type<1>> w;
}
演绎将
wrapper<my_type<1>>
与 wrapper<my_type<Arg>>
进行比较。在此推导的背景下,Arg
可推导为 1
。