我正在尝试编写一个智能指针包装器(包含一个boost shared_ptr或scoped_ptr或另一个智能指针包装器);每个包装器类型注入一些额外的功能(例如,记录使用,延迟初始化,验证正确的构造/销毁顺序等)但我希望它们对用户尽可能不可见(这样我可以交换/输出包装器只需更改单个typedef,可能还有一些构造函数代码,但不包括任何使用代码。)
正常使用是微不足道的:
template<typename T>
class some_smart_ptr_wrapper
{
public:
typedef typename T::value_type value_type;
...
value_type* get() { /*do something magic*/ return m_ptr.get(); }
const value_type* get() const { /*do something magic*/ return m_ptr.get(); }
// repeat for operator->, operator*, and other desired methods
private:
T m_ptr;
};
typedef some_smart_ptr_wrapper< boost::shared_ptr<int> > smart_int;
smart_int p;
(现在所有其他代码都可以使用p
与shared_ptr无法区分,至少对于已定义的操作,我只需更改typedef即可添加额外的包装。)
只需按照您的预期嵌套它们,就可以同时使用多个包装器,只有声明(有时初始化)变量的代码需要关注。
有时候能够从包装器中获取“basic”shared / scoped_ptr是有用的(特别是将shared_ptr作为参数传递给不需要触发包装器添加的功能的函数);对于单个包装层,它很容易:
T& getPtr() { return m_ptr; }
const T& getPtr() const { return m_ptr; }
但是这不能很好地扩展到多个包装层(调用者必须执行p.getPtr().getPtr().getPtr()
正确的次数。)
我希望能够做的是声明getPtr():
其最终结果是从外部代码单次调用getPtr()会将链“向上”到原始智能指针,因为这将是唯一一个不实现getPtr()的指针。
我很确定该解决方案将涉及SFINAE和boost :: enable_if;我试图让这样的东西起作用,但到目前为止还没有多少运气。
解决方案或完全替代的方法都受到欢迎;请注意,我希望它可以在VC ++ 2008和GCC中工作(即,遗憾的是没有C ++ 11)。
答案 0 :(得分:1)
(1)声明一个特殊的成员类型名称,其内部是唯一的:
template<typename T>
class some_smart_ptr_wrapper
{
public:
typedef T smart_type; // <-- unique name
...
};
(2)在模板函数包装器中包装getPtr()
:
template<typename T>
class some_smart_ptr_wrapper
{
...
public:
T& getPtr () { return m_ptr; }
typename My_sfinae<T>::RealType& getFinalPtr ()
{ return My_sfinae<T>::getPtr(m_ptr); }
...
};
(3)My_sfinae
照常实施的地方:
template<typename T>
struct void_ { typedef void type; };
template<typename T, typename = void>
struct My_sfinae {
typedef T RealType;
static T& getPtr (T &p) { return p; }
}; //^^^^^^^^^ business logic!
template<typename T>
struct My_sfinae<T, typename void_<typename T::smart_type>::type> {
typedef typename My_sfinae<typename T::smart_type>::RealType RealType;
static RealType& getPtr (T &p)
{ return My_sfinae<typename T::smart_type>::getPtr(p.getPtr()); }
};
正如您所看到的,My_sfinae
会移除所有包装递归,最后您将获得最终m_ptr
。
答案 1 :(得分:1)
实际上,这是一个简单的问题:只需使用重载:)
template <typename T>
boost::scoped_ptr<T>& get_pointer(boost::scoped_ptr<T>& sp) { return sp; }
template <typename T>
boost::shared_ptr<T>& get_pointer(boost::shared_ptr<T>& sp) { return sp; }
// One overload per "wrapper"
template <typename T>
typename get_pointer_type<T>::type& get_pointer(some_wrapper<T>& p) {
return get_pointer(p.getPtr());
}
然后诀窍是为每个包装器正确地专门化get_pointer_type
。
template <typename T>
struct get_pointer_type { typedef T type; };
template <typename T>
struct get_pointer_type< some_wrapper<T> > {
typedef typename get_pointer_type<T>::type type;
};
答案 2 :(得分:0)
最让我想到的是由Bjarne Stroustrup撰写的论文Wrapping C++ Member Function Calls。
本文提出了一个简单,通用,有效的解决旧问题的方法 ''wrap''以成对的前缀和后缀代码调用对象。解决方案也是 非侵入式,适用于现有类,允许使用多个前缀/后缀对,以及 可以用标准C ++的15个简单行来实现。一个强大的包装版本 也出席了。效率的要求得到了衡量的支持。