Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/templates/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 用方法替换包装智能指针_C++_Templates_Smart Pointers_Sfinae - Fatal编程技术网

C++ 用方法替换包装智能指针

C++ 用方法替换包装智能指针,c++,templates,smart-pointers,sfinae,C++,Templates,Smart Pointers,Sfinae,我正在尝试编写一个智能指针包装器(包含一个boost shared_ptr或scoped_ptr或另一个智能指针包装器);每种包装类型都注入了一点额外的功能(例如,记录使用情况、惰性初始化、验证正确的构造/销毁顺序等),但我希望它们对用户尽可能不可见(这样,我只需更改一个typedef,以及可能的一些构造函数代码,但不更改任何使用代码,就可以交换入/出包装) 正常使用非常简单: template<typename T> class some_smart_ptr_wrapper { p

我正在尝试编写一个智能指针包装器(包含一个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.getPtr().getPtr().getPtr()
正确的次数)

我希望能够声明getPtr(),以便:

  • 如果T实现getPtr(),那么它将返回m_ptr.getPtr()(不管是什么类型)
  • 如果T没有实现getPtr(),那么它将返回m_ptr
  • 正如您所期望的,它仍然有常量和非常量两种口味
其最终结果是,外部代码对getPtr()的单个调用将“向上”到原始智能指针的链,因为这将是唯一一个没有实现getPtr()的

我相当确信解决方案将涉及SFINAE和boost::enable_if;我一直在努力让这样的东西发挥作用,但迄今为止运气不太好


双方都欢迎解决办法或完全替代办法;请注意,我希望它能同时在VC++2008和GCC中工作(遗憾的是,没有C++11)。

我脑海中浮现的最贴切的东西是比亚恩·斯特劳斯特鲁普写的一篇论文,名为

本文提出了一种简单、通用和有效的解决方案,解决了传统的 “包装”以前缀和后缀代码对对象进行调用。解决方案也是可行的 非侵入性,适用于现有类,允许使用多个前缀/后缀对,以及 可以用标准C++的15个简单行来实现。包装器的健壮版本 本文还介绍了该方法。效率的主张得到了衡量的支持

(1) 声明内部唯一的特殊成员typename:

template<typename T>
class some_smart_ptr_wrapper
{
public:
  typedef T smart_type;  // <-- unique name
...
};
(3) 其中,
My\u 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()); }
};
模板
结构void{typedef void type;};
模板
构造我的\u sfinae{
typedef T RealType;
静态T&getPtr(T&p){return p;}
};                        //^^^^^^^^^ 商业逻辑!
模板
构造我的\u sfinae{
typedef typename My_sfinae::RealType RealType;
静态RealType和getPtr(T&p)
{返回My_sfinae::getPtr(p.getPtr());}
};
正如您所看到的,
My\u sfinae
递归地删除所有包装,最后只剩下最后的
m\u ptr


.

实际上,这是一个简单的问题:只需使用重载(:)


我真的不知道这对OP有什么帮助,也许一点示例代码会有帮助?我只能建议大家更仔细地研究一下。那么请告诉我,OP并不是在寻找一种用前缀和后缀代码包装函数调用的方法(除非我完全误解了这个问题),他希望递归调用某个函数,直到到达基类型。我的问题的前半部分是关于用前缀执行代码包装一个类,这篇论文与之相关——然而,虽然它比我在问题中发布的内容更通用,但它并没有真正起到帮助作用,因为我试图拦截对智能指针本身的调用,而不是指向的对象。(虽然有可能做到这一点,但这将打破当前的使用和“智能指针”概念。)下半部分是关于折叠调用树以获得底层智能指针,这是一个更有趣的问题,我看不出这有什么帮助。很好的解决方案。一般来说,我更喜欢traits类而不是侵入式修改(因为它允许在你不拥有的类上调整行为),但SFINAE的核心原则确实是个好主意。我不知道这是怎么回事。请记住,在共享的\u ptr中,T是实际类型,在第一级包装中,T是共享的\u ptr,在第二级包装中,T是第一级\u包装,等等。在第二级包装上调用getPtr()应该返回共享的\u ptr,而不是该包装类型的T。@Miral,我在代码中提到,您需要使用
getFinalPtr()
而不是
getPtr()
。您可以重命名此方法以获得所需的输出。我的观点是,
getFinalPtr()
的返回值不可能是T,除非只有一层包装,在这种情况下根本不需要它。如果我调用
p.getFinalPtr()
其中p的类型为
wrapper3
它必须返回一个
共享的\u ptr&
@Miral,经过多次努力,用有效的解决方案编辑了我的答案。与演示一起检查它。它是用c++0x编译的,只是为了支持
std::shared_ptr
,否则使用的特性是c++03。如果仍然面临问题,请告诉我。C++03最简单、最好的解决方案,+1.Btw是一个更好的C++11版本,甚至感觉有点像Haskell的模式匹配。请注意,GCC无法在该版本中编译,但Clang 3.1编译得很好,因为它涉及用户定义的类型。@Xeo:不知道最简单的方法(因为它要求每个包装都有一个重载和一个专门化),我也很喜欢IAmilid的解决方案;但我确实同意,
decltype
只是一个魔术:)尽管GCC4.7似乎在这一点上受阻,但我会再次确认它是否真的被允许以这种方式工作(不过,我不想明确说明每个支持的指针类型,也不想使用自由函数;我更喜欢成员函数。
value\u-type
应该是
element\u-type
并且您应该只有一个
get
成员:
element\u-type*get()常量;
。常量指针并不意味着指针对象是常量
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); }
...
};
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()); }
};
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());
}
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;
};