为何无法传递unique_ptr<Derived<T>>给接收unique_ptr<Base<T>>的函数?如何修复?
问题原因
直接把std::unique_ptr<Derived<int>>转换成std::unique_ptr<Base<int>>能成功,是因为标准库允许unique_ptr从派生类指针的实例移动构造基类指针的实例,这是合法的隐式转换。
但调用模板函数/构造函数时出错,核心问题在模板参数推导环节:
当你写foo(std::move(b)),编译器需要推导模板参数T。此时实参类型是std::unique_ptr<Derived<int>>,形参是std::unique_ptr<Base<T>>——模板推导只会做直接类型匹配,不会自动沿着继承关系反向推导Base<T>里的T应该对应Derived<int>的int。简单说,编译器没法把Derived<int>和Base<T>关联起来,自然推导不出正确的T,也就无法触发后续的unique_ptr转换规则。
修复方法
有三种实用的修复方式:
1. 显式指定模板参数
调用时直接告诉编译器T的类型,跳过自动推导:
int main() { auto b = std::make_unique<Derived<int>>(); foo<int>(std::move(b)); MyClass<int> mc(std::move(b)); }
2. 修改模板,支持任意可转换的unique_ptr
把函数或构造函数改成接受任意unique_ptr类型,再利用继承关系完成转换:
针对函数foo:
template <typename Derived> void foo(std::unique_ptr<Derived> ptr) { // 直接转换为Base<T>的unique_ptr,T对应Derived的模板参数 std::unique_ptr<Base<typename Derived::element_type::value_type>> base_ptr = std::move(ptr); // 后续逻辑使用base_ptr即可 }
针对MyClass:
把构造函数改成模板,接受任意派生类的unique_ptr:
class MyClass { public: template <typename Derived> MyClass(std::unique_ptr<Derived> arg) : _arg(std::move(arg)) {} // 直接利用unique_ptr的移动构造转换 private: std::unique_ptr<Base<typename Derived::element_type::value_type>> _arg; };
如果使用C++20及以上版本,还可以加约束确保Derived确实继承自Base<T>:
template <typename Derived> requires std::is_base_of_v<Base<typename Derived::element_type::value_type>, Derived::element_type> void foo(std::unique_ptr<Derived> ptr) { // ... }
3. 手动提前转换
在调用前先把unique_ptr<Derived<int>>转换成unique_ptr<Base<int>>,再传递:
int main() { auto b = std::make_unique<Derived<int>>(); std::unique_ptr<Base<int>> base_b = std::move(b); foo(std::move(base_b)); MyClass mc(std::move(base_b)); }
内容的提问来源于stack exchange,提问作者Dmitry Kuznetsov
相关产品推荐
相关产品推荐

