Boost(二):assign
(一) assign重载的运算符
assign库为所有的标准容器重载了‘+=’‘,’‘()’运算符,使得可以更方便地为标准容器初始化和赋值。
如:vector values;
values+= 1,2,3,4,5;
我们先了解一下各个运算符重载的实现,以vector为例:
template< class V, class A, class V2 >
inline list_inserter< assign_detail::call_push_back< std::vector<V,A> >, V >
operator+=( std::vector<V,A>& c, V2 v )
{
return push_back( c )( v );
}
第一行代码无需多讲,第二行的 list_inserter类非常关键,它是使用或连接着三个操作符的工具。
我们可以看到assign重载的+=运算符,它返回一个list_inserter类。实际上,assign库只重载了+=运算符,而‘,’‘()’都由list_inserter类来完成,也就是说,+=运算符负责得到一个list_inserter类,剩下的工作都由list_inserter来完成。这里我们可以先放一放这个工具类,先来了解一下assign库提供的工厂函数push_back,这里是它的源码:
push_back( C& c )
{
static BOOST_DEDUCED_TYPENAME C::value_type* p = 0;
return make_list_inserter( assign_detail::call_push_back<C>( c ),
p );
}
再来看看call_push_back的具体内容:
template< class C >
class call_push_back
{
C& c_;
public:
call_push_back( C& c ) : c_( c )
{ }
template< class T >
void operator()( T r )
{
c_.push_back( r );
}
};
这样一来,push_back函数的功能就很明确了,通过对需要操作的容器C指定类型,然后掉用C容器的push_back成员函数将value加入容器,然后构造一个调用容器成员函数的类call_push_back再去构造一个list_inserter类。多说无益,我们直接来看list_inserter类的成员变量及函数:
template<class Function>
class list_inserter
{
public:
list_inserter& operator,(const T& r);
list_inserter& operator()();
list_inserter& operator()(const T& t);
private:
Function insert_;
}
其中insert_成员变量就是由call_push_back来初始化的;
list_inserter& operator()()
{
insert_( Argument() );
return *this;
}
list_inserter& operator,( const T& r )
{
insert_( r );
return *this;
}
之后就是由list_inserter所重载的‘,’‘()’运算符来完成工作。
(二)用于初始化容器的工厂函数
list_of()
map_list_of/pair_list_of()
tuple_list_of()
使用: vector values = list_of(1)(2)(3);
使用之前的+=操作不得不先构造容器后赋值,而这三个工厂函数提供了更快捷的构造方法,即在构造时初始化容器。
我们先来看看它的源码:
template< class T >
inline assign_detail::generic_list<T>
list_of( const T& t )
{
return assign_detail::generic_list<T>()( t );
}
它返回一个generic_list,这是不是和之前的list_inserter很像?没错,list_inserter将容器的insert类操作隐藏,仅仅使用+=就可以完成所有容器的赋值操作。同样,generic_list将容器类型转化的过程隐藏,使用list_of就可以完成初始化。需要注意的是,list_of在‘,‘’()’一起使用的情况下,需要对list_of表达式加括号,否者编译器无法推断返回类型。
template< class T >
class generic_list :
public converter< generic_list< BOOST_DEDUCED_TYPENAME assign_decay<T>::type >,
BOOST_DEDUCED_TYPENAME std::deque<BOOST_DEDUCED_TYPENAME
assign_decay<T>::type>::iterator >
{
typedef assign_decay<T>::type Ty;
typedef std::deque<Ty> impl_type;
mutable impl_type values_;
public:
typedef BOOST_DEDUCED_TYPENAME impl_type::iterator iterator;
typedef iterator const_iterator;
typedef BOOST_DEDUCED_TYPENAME impl_type::value_type value_type;
typedef BOOST_DEDUCED_TYPENAME impl_type::size_type size_type;
typedef BOOST_DEDUCED_TYPENAME impl_type::difference_type difference_type;
public:
iterator begin() const { return values_.begin(); }
iterator end() const { return values_.end(); }
bool empty() const { return values_.empty(); }
size_type size() const { return values_.size(); }
private:
void push_back( value_type r ) { values_.push_back( r ); }
public:
generic_list& operator,( const Ty& u )
{
this->push_back( u );
return *this;
}
generic_list& operator()( const Ty& u )
{
this->push_back( u );
return *this;
}
template< class Container >
operator Container() const
{
return this-> BOOST_NESTED_TEMPLATE convert_to_container<Container>();
}
这么多看不下去也没关系,这里的源码不需要全部看完,类继承和类型声明都可以先跳过,关键是这几段:
1.
typedef assign_decay<T>::type Ty;
typedef std::deque<Ty> impl_type;
mutable impl_type values_;
这里声明了一个deque成员变量,至于Ty我们先不管;
2.
public:
iterator begin() const { return values_.begin(); }
iterator end() const { return values_.end(); }
bool empty() const { return values_.empty(); }
size_type size() const { return values_.size(); }
private:
void push_back( value_type r ) { values_.push_back( r ); }
public:
generic_list& operator,( const Ty& u )
{
this->push_back( u );
return *this;
}
generic_list& operator()( const Ty& u )
{
this->push_back( u );
return *this;
}
看到这些是不是就有些清楚了?其实generic_list内部的操作都是转化成deque来完成的,每次使用‘,’’()‘运算符,都会调用deque的push_back成员函数来完成操作,那么剩下的就是类型转化问题了,而
template< class Container >
operator Container() const
{
return this-> BOOST_NESTED_TEMPLATE convert_to_container<Container>();
}
这段代码提供了generic_list所有类型的转化操作,我们再接着看下去。
template< class Container >
Container convert_to_container() const
{
static Container* c = 0;
BOOST_STATIC_CONSTANT( bool, is_array_flag =
sizeof( assign_detail::assign_is_array( c ) )
== sizeof( type_traits::yes_type ) );
typedef BOOST_DEDUCED_TYPENAME mpl::if_c< is_array_flag,
array_type_tag,
default_type_tag >::type tag_type;
return convert<Container>( c, tag_type() )
}
private:
template< class Container >
Container convert( const Container*, default_type_tag ) const
{
return Container( begin(), end() );
}
这两个函数均为converter的成员函数(converter为generic_list的父类),其真正做的内容就是把generic_list的deque的首位迭代器用于构建一个新的容器,所以,当编译器无法推断list_of的隐式转换类型时,转换就无法正常执行。
(三)一些*函数
repeat()
使用方法:vector v;
v += 1,2,3,repeat(10,4),5,6;
结合之前得内容,这里的操作就很好分析,repeat在内部使用并返回list_inserter类来完成该操作。
repeat_fun()
和repeat()一样,只是把其value参数换成了function;
range()
range函数有两种重载,第一种的参数为Container,第二种为两个迭代器,和标准容器的操作类似。
ref_list_of()&cref_list_of
这两个函数用于快速创建匿名的容器
int& max = *max_element(ref_list_of<3>(a)(b)(d));
上一篇: Boost beast 使用例子
下一篇: css怎么让文字不换行