C++11参数隐式转换问题:模板函数无法适配的原因与解决方法
问题背景
首先是Prop类的实现代码:
template <typename T> class Prop { public: Prop(const std::function<T()> &getter) : getter(getter) {} Prop(const T &value) : getter([=]() { return value; }) Prop(const char *value) : getter([=]() { return std::string(value); }) T operator()() const { return getter(); } private: const std::function<T()> getter; };
当把值传递给非模板函数时可以触发隐式转换,但传递给模板函数时会编译失败:
void foo(const Prop<int> &prop) {} template <typename T> void bar(const Prop<T> &prop) {} int main() { foo(0); // 正常编译,隐式转换生效 bar(0); // 编译报错:no instance of function template "bar" matches the argument list }
现象产生的原因
- 对于非模板函数
foo,参数类型是明确的Prop<int>,编译器清楚知道需要把int类型的0通过Prop<int>的构造函数(Prop(const T &value))隐式转换成Prop<int>对象,这完全符合C++隐式转换的规则。 - 对于模板函数
bar,编译器需要先推导模板参数T的具体类型。但模板参数推导的规则是:只会直接匹配实参与形参的类型,不会触发隐式转换来辅助推导。这里实参是int类型的0,形参是const Prop<T>&,两者没有直接的类型匹配关系,编译器无法推导出T的类型,因此编译报错。
让模板函数支持隐式转换的方案
方案1:显式指定模板参数
调用bar时直接告诉编译器T的类型,此时编译器无需推导,就能正常触发隐式转换:
bar<int>(0); // 编译通过,0会被隐式转换成Prop<int>
方案2:拆分参数推导逻辑
通过重载函数,先让编译器推导出实参的原始类型,再手动构造Prop对象传递给真正的模板逻辑:
// 原模板逻辑放在这里 template <typename T> void bar_impl(const Prop<T> &prop) { // 这里写bar原本的业务代码 } // 重载一个通用函数,先推导实参类型U,再构造Prop<U> template <typename U> void bar(U &&value) { bar_impl(Prop<U>(std::forward<U>(value))); } // 调用时正常传值即可 bar(0); // 编译通过,U被推导为int,再构造Prop<int>传入bar_impl
内容的提问来源于stack exchange,提问作者Tempus
相关产品推荐
相关产品推荐

