c – 为什么shared_ptr不能解析函数接口中的继承关系?
这是一个
simplified example:
#include <memory> #include <vector> template< class T > class K { public: virtual ~K(){} }; class KBOUM : public K<int>{}; template< class U > void do_something( std::shared_ptr< K<U> > k ) { } int main() { auto kboom = std::make_shared<KBOUM>(); do_something( kboom ); // 1 : error std::shared_ptr< K<int> > k = kboom; // 2 : ok do_something( k ); // 3 : ok } 无论有没有提升,无论我使用何种编译器,我都会在#1上遇到错误,因为shared_ptr< KBOOM>不要从shared_ptr< K< int>>继承. 所以我的问题是: >什么阻止std :: shared_ptr实现者使它在#1的情况下工作(我的意思是,假设标准确实阻止了这种情况,应该有一个原因); 注意:我想避免函数的用户必须写 std::shared_ptr<K<int>> k = std::make_shared<KBOOM>(); 要么 do_something( std::shared_ptr<K<int>>( kboom ) ); 解决方法
这与std :: shared_ptr<>无关.实际上,您可以将其替换为任何类模板并获得相同的结果:
template<typename T> struct X { }; class KBOUM : public X<int> { }; template<typename U> void do_something(X<K<U>> k) { } int main() { X<KBOUM> kboom; do_something(kboom); // ERROR! X<K<int>> k; do_something(k); // OK } 这里的问题是类型参数推导试图找到完美匹配,并且不尝试派生到基础的转换. 只有在明确推断出所有模板参数以产生完美匹配(标准允许的少数例外)之后,才会在重载决策期间考虑参数之间的可能转换. 解决方法: 可以根据KerrekSB在this Q&A on StackOverflow发布的解决方案找出解决方法.首先,我们应该定义一个类型特征,它允许我们判断某个类是否来自某个模板的实例: #include <type_traits> template <typename T,template <typename> class Tmpl> struct is_derived { typedef char yes[1]; typedef char no[2]; static no & test(...); template <typename U> static yes & test(Tmpl<U> const &); static bool const value = sizeof(test(std::declval<T>())) == sizeof(yes); }; 然后,我们可以使用SFINAE重写do_something(),如下所示(注意C 11允许函数模板参数的默认参数): template<class T,std::enable_if<is_derived<T,K>::value>* = nullptr> void do_something(X<T> k) { // ... } 通过这些更改,程序将正确编译: int main() { X<KBOUM> kboom; do_something(kboom); // OK X<K<int>> k; do_something(k); // OK } 这是一个live example. (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |