Kla*_*aim 3 c++ templates boost c++11
这是一个简化的例子:
#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
}
Run Code Online (Sandbox Code Playgroud)
有或没有boost,无论我使用什么编译器,我都会在#1上遇到错误,因为shared_ptr<KBOOM>不会继承shared_ptr<K<int>>.但是,KBOOM继承自K<int>.您可以看到#2有效,因为shared_ptr旨在允许隐式地将子类指针传递给基类指针,就像原始指针一样.
所以我的问题是:
auto kboom = std::make_shared<KBOUM>(); do_something( kboom );不查看KBOOM继承的K的int类型的情况下编写?注意:我想避免函数的用户必须写
std::shared_ptr<K<int>> k = std::make_shared<KBOOM>();
Run Code Online (Sandbox Code Playgroud)
要么
do_something( std::shared_ptr<K<int>>( kboom ) );
Run Code Online (Sandbox Code Playgroud)
这与此无关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
}
Run Code Online (Sandbox Code Playgroud)
这里的问题是类型参数推导试图找到完美匹配,并且不尝试派生到基础的转换.
只有在明确推断出所有模板参数以产生完美匹配(标准允许的少数例外)之后,才会在重载决策期间考虑参数之间的可能转换.
解决方法:
可以根据KerrekSB在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);
};
Run Code Online (Sandbox Code Playgroud)
然后,我们可以使用SFINAE重写do_something()如下(注意C++ 11允许函数模板参数的默认参数):
template<class T, std::enable_if<is_derived<T, K>::value>* = nullptr>
void do_something(X<T> k)
{
// ...
}
Run Code Online (Sandbox Code Playgroud)
通过这些更改,程序将正确编译:
int main()
{
X<KBOUM> kboom;
do_something(kboom); // OK
X<K<int>> k;
do_something(k); // OK
}
Run Code Online (Sandbox Code Playgroud)
这是一个实例.