欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Boost(二):assign

程序员文章站 2022-03-03 19:20:55
...

(一) 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));