为何指定部分模板参数后,编译器无法推导剩余的模板参数?
为何指定部分模板参数后,编译器无法推导剩余的模板参数?
这个问题其实戳中了C++类模板实参推导(CTAD)的一个关键规则限制——只有当你完全不指定任何模板参数时(也就是写Obj obj{x}这种不带<>的形式),编译器才会自动通过构造函数的参数来推导所有模板参数。一旦你显式指定了部分模板参数(比如Obj<1>),编译器就会默认你要固定这些已给出的参数,剩余的参数必须要么显式补全,要么靠专门的推导指引来辅助,默认的构造函数推导逻辑直接就不生效了。
咱们拿你的代码对比着看就明白:
- 对于
Obj2 obj2{x};:你没写任何模板参数,编译器可以顺着构造函数的S<T>*参数,反向推导出T=double、S=dummy,完美匹配Obj2的模板参数列表,所以推导成功。 - 对于
Obj<1> obj{x};:你已经明确指定了第一个模板参数dummy_parameter=1,这时候编译器就会要求你把剩下的T和S也显式写出来(比如Obj<1, double, dummy> obj{x}),不会再去用构造函数的参数帮你推导这两个剩余参数——这是C++标准里明确规定的CTAD适用范围。
如果想实现你要的“只指定第一个int参数,让编译器推导剩下的”需求,有两种常用的解决办法:
方法1:添加类模板推导指引
你可以给Obj专门写一个推导指引,告诉编译器当我们指定第一个int参数时,怎么从构造函数参数推导剩余参数:
// 固定第一个参数为1的版本 template <typename T, template <typename> typename S> Obj(S<T>*) -> Obj<1, T, S>;
如果想支持任意int值,就写更通用的版本:
template <int N, typename T, template <typename> typename S> Obj(N, S<T>*) -> Obj<N, T, S>;
这时候调用要改成带第一个int参数的形式:
auto obj = Obj{1, x};
方法2:用工厂函数封装
写一个模板工厂函数,把第一个int参数作为显式模板参数,剩下的参数通过函数参数自动推导:
template <int N, typename T, template <typename> typename S> auto make_obj(S<T>* data) { return Obj<N, T, S>{data}; }
调用的时候就很直观了:
auto obj = make_obj<1>(x);
这种方式不需要额外的推导指引,在C++代码里很常用,用来解决这类部分模板参数推导的场景。
备注:内容来源于stack exchange,提问作者Saitama10000
相关产品推荐
相关产品推荐

