引用文件: 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
可以看出,通过返回值的偏特化,获取里面最原始的类型。
以上分析权当学习笔记以记之。