您的位置:首页 > 其它

boost 源码 ref 库分析

2014-02-13 22:40 351 查看
引用文件: boost/ref.hpp

一般情况下,泛型算法中的函数对象,传值语义是可行的,但是也有很多特殊情况,作为参数的函数对象拷贝代价过高(具有复杂的内部状态),或者不希望拷贝对象(内部状态不应该被改变),甚至拷贝是不可行的(noncopyable,单件)。

boost.ref应用代理模式,引入对象引用的包装器概念解决了这个问题。

template<class T> class reference_wrapper
{
public:
typedef T type;

#if defined( BOOST_MSVC ) && BOOST_WORKAROUND( BOOST_MSVC, < 1300 )
explicit reference_wrapper(T& t): t_(&t) {}
#else
explicit reference_wrapper(T& t): t_(boost::addressof(t)) {}
#endif

operator T& () const { return *t_; }
T& get() const { return *t_; }
T* get_pointer() const { return t_; }

private:
T* t_;
};

从代码中可以看出,其实就是保存了所封装的对象的指针。所以可以达到拷贝甚至快速拷贝的目的。

boost::addressof 的实现就是取该对象的地址。

template<class T> T * addressof( T & v )
{
#if (defined( __BORLANDC__ ) && BOOST_WORKAROUND( __BORLANDC__, BOOST_TESTED_AT( 0x610 ) ) ) || defined( __SUNPRO_CC )

return boost::detail::addressof_impl<T>::f( v, 0 );

#else

return boost::detail::addressof_impl<T>::f( boost::detail::addr_impl_ref<T>( v ), 0 );

#endif
}


boost::detail::addr_impl_ref 简单的对象封装。不可赋值拷贝。而addressof_impl的实现如下

template<class T> struct addressof_impl
{
static inline T * f( T & v, long )
{
return reinterpret_cast<T*>(
&const_cast<char&>(reinterpret_cast<const volatile char &>(v)));
}

static inline T * f( T * v, int )
{
return v;
}
};


f函数的实现,如此费工夫转换来转换去,目的是防止自定义的operator T*() 的操作符重载。

reference_wrapper的名字过长,声明引用包装对象很不方便,因而ref库提供了两个便捷的工厂函数ref() 和 cref(),可以通过参数类型推导很容易的构造reference_wrapper对象。

参见如下示例。

VECINT vecInt;
int intArray[] = {2,3,4,5,6,7,8,9};
vecInt.assign(intArray,intArray+_countof(intArray));

reference_wrapper<std::vector<int>> rw1 = boost::ref(vecInt);

BOOST_AUTO(rw1,boost::ref(vecInt));

if(is_reference_wrapper<BOOST_TYPEOF(rw1)>::value)
std::cout << typeid(rw1).name() << std::endl;
std::cout << rw1.get()[0] << std::endl;
std::cout << unwrap_ref(rw1)[1] << std::endl;


看看ref()的定义

template<class T> inline reference_wrapper<T> BOOST_REF_CONST ref(T & t)
{
return reference_wrapper<T>(t);
}


简单的封装,

解封装函数unwrap_ref定义如下

template <class T> inline typename unwrap_reference<T>::type&
unwrap_ref(T& t)
{
return t;
}


因为返回值是不参与类型推演的。所以有了unwrap_reference模板,另外typename关键字不能少,否则type会被当作unwrap_reference的成员变量,而不是一个类型。

【补】对于这个例子

std::cout << unwrap_ref(rw1)[1] << std::endl;
按上面的源码解释不通,看样子是返回reference_wrapper,是不能直接[]操作,通过再次阅读源码发现有如下宏:

#  define AUX_REFERENCE_WRAPPER_METAFUNCTIONS_DEF(X) \
template<typename T> \
class is_reference_wrapper< X > \
: public mpl::true_ \
{ \
}; \
\
template<typename T> \
class unwrap_reference< X > \
{ \
public: \
typedef T type; \
}; \
/**/

AUX_REFERENCE_WRAPPER_METAFUNCTIONS_DEF(reference_wrapper<T>)
#if !defined(BOOST_NO_CV_SPECIALIZATIONS)
AUX_REFERENCE_WRAPPER_METAFUNCTIONS_DEF(reference_wrapper<T> const)
AUX_REFERENCE_WRAPPER_METAFUNCTIONS_DEF(reference_wrapper<T> volatile)
AUX_REFERENCE_WRAPPER_METAFUNCTIONS_DEF(reference_wrapper<T> const volatile)
#endif
可以看出,通过返回值的偏特化,获取里面最原始的类型。

以上分析权当学习笔记以记之。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: