我有一个类,它封装了一个通用的 "智能指针"(可以是 unique_ptr
, shared_ptr
等)。)
我试图将构造函数特殊化,以便调用适当的 make_unique
, make_shared
等,但我不知道正确的语法。
下面是我的想法(实况转播):
template <class SmartPtr>
struct Holder {
typedef typename SmartPtr::element_type value_type;
Holder()
: m_ptr(new value_type) // The fallback implementation calls 'new' directly.
{}
private:
SmartPtr m_ptr;
};
// THIS DOES NOT COMPILE
// Notice the "T" type, which is not declared anywhere.
// How do I declare this sort of thing properly?
template<>
Holder<shared_ptr<T>>::Holder
: m_ptr(make_shared<T>())
{}
我想基于智能指针进行专门化 但我也需要访问智能指针管理的底层类型。
这是C++14,但我对其他标准的想法也很感兴趣。
EDIT: 一些类似的问题,但在这种情况下并不完全适用(或者即使适用,我也不清楚所需的转换)。
不考虑语法错误,你的代码不能编译的原因是,你不能部分特殊化函数模板,你只能部分特殊化类模板。但是,你可以重载函数。使用函数重载来解决这个问题,一点也不容易。我在下面详细介绍了两种技术,你可以用这两种技术来解决你的问题,其中第二种技术是利用部分模板特化。
首先,假设你有一个C++17编译器,你可以使用 if constexpr
和模板编程来获得理想的效果。
template <class SmartPtr>
struct Holder {
//this is a nested helper struct, which will allow us to deduce at compile-time
// whether SmartPtr is a std::unique_ptr or not, using function overloading
template<typename T>
struct is_unique_ptr{
template<typename TT>
constexpr static std::true_type test(std::unique_ptr<TT>*);
constexpr static std::false_type test(...);
using type = decltype(test(std::declval<T*>()));
constexpr static bool value = type::value;
};
//this is a nested helper struct, which will allow us to deduce at compile-time
// whether SmartPtr is a std::shared_ptr or not, using function overloading
template<typename T>
struct is_shared_ptr{
template<typename TT>
constexpr static std::true_type test(std::shared_ptr<TT>*);
constexpr static std::false_type test(...);
using type = decltype(test(std::declval<T*>()));
constexpr static bool value = type::value;
};
typedef typename SmartPtr::element_type value_type;
//default constructor will conditionally construct m_ptr depending on its type
Holder(){
if constexpr(is_unique_ptr<SmartPtr>::value){
m_ptr = std::make_unique<value_type>();
} else if constexpr(is_shared_ptr<SmartPtr>::value){
m_ptr = std::make_shared<value_type>();
} else {
m_ptr = new value_type{};
}
}
private:
SmartPtr m_ptr;
};
这个解决方案没有使用部分模板特化。然而如果你坚持使用部分模板特化,或者你没有c++17编译器,你将不得不对整个类进行不同指针类型的特化。
//generic class Holder (identical to your initial implementation)
template <class SmartPtr>
struct Holder {
typedef typename SmartPtr::element_type value_type;
Holder()
: m_ptr(new value_type){
}
private:
SmartPtr m_ptr;
};
//this partial specialisation will be selected if template parameter is a std::unique_ptr
template<typename T>
struct Holder<std::unique_ptr<T>>{
using value_type = T;
Holder() : m_ptr(std::make_unique<value_type>()){
}
private:
std::unique_ptr<T> m_ptr;
};
//this partial specialisation will be selected if template parameter is a std::unique_ptr
template<typename T>
struct Holder<std::shared_ptr<T>>{
using value_type = T;
Holder() : m_ptr(std::make_shared<value_type>()) {
}
private:
std::shared_ptr<T> m_ptr;
};
使用部分模板特化,像这样,会导致代码膨胀。如果你决定使用这种解决方案,你可能需要考虑将常用方法分解到一个基类中,所有的特殊化都从这个基类中继承。这将有助于减少代码的臃肿。
我想我想明白了这一点 (实况转播):
关键是要有一个模板化的构造函数,并带有 enable_if
确定它是否是一个有效的选择。
template <class SmartPtr>
struct Holder {
typedef typename SmartPtr::element_type value_type;
Holder()
: m_ptr(new value_type)
{}
template <class T = value_type>
Holder(std::enable_if_t< std::is_same<shared_ptr<T>,SmartPtr>::value >* = 0)
: m_ptr(make_shared<T>())
{}
private:
SmartPtr m_ptr;
};
可能还有更好的方法---------------------------------。is_same
检查似乎有点黑客。但现在已经很好了。