На использование, модификацию и распространение распространяется лицензия Boost Software License, версия 1.0 (см.http://www.boost.org/LICENSE_1_0.txt).
Практических применений оператора, по-видимому, немного. Бьярн СтрауструпДизайн и эволюция C++ Bjarne
Stroustrup, The Design and Evolution of C++ [ORIG_END] -->
Цель этой библиотеки состоит в том, чтобы облегчить заполнение контейнеров данными путем перегрузкиоператора,иоператора () ().. Эти два оператора позволяют создавать списки значений, которые затем копируются в контейнер:
A comma-separated list:
вектор<int>v;v+=,1,2,3,4,5,6,7,8,9;
vector<int> v; v += 1,2,3,4,5,6,7,8,9;
[ORIG_END] -->
A parenthesis-separated list:
картастрока,int>m;вставкаm]"Bar",1],2;
Эти списки особенно полезны в ситуациях обучения, тестирования и прототипирования, но также могут быть удобны в противном случае. Библиотека поставляется с предопределенными операторами для контейнеров стандартной библиотеки, но большинство функций будет работать с любым стандартным контейнером. Библиотека также позволяет расширить типы, определенные пользователем, так что, например, функция-член может быть вызвана для списка значений вместо обычных аргументов.
Tutorial
В течение двух минут вы сможете пользоваться этой библиотекой. Основные компоненты объяснены в этих разделах:
Функция
Функция
Функция
ФункцияФункцииповторяют,повторяютидиапазонref_list_ofи[[[ Две первые функции используются для добавления элементов после создания контейнерного объекта, в то время как следующие две используются, когда нам нужно инициализировать объект.
Function operator+=()
Для заполнения вектора (или любого стандартного контейнера) значениями с использованием оператора+=()вы пишете
#включитеутверждаетBOOST_ASSERTзначения[]
9BOOST_ASSERT[ Здесь мы только засунули константы в контейнер, но список может состоять из произвольных выражений, если результат каждого выражения конвертируется взначение_типконтейнера.
Function operator()()
Мы не называемоператор()()напрямую, но вместо этого мы называем функцию, которая возвращает прокси-объект, который определяетоператор()(). Функция, возвращающая прокси-объект, всегда называется в честь функции-члена, которая используется для копирования значений в списке в контейнер. Итак, чтобы заполнить карту парами значений вы пишете
присвоитьприсвоитьприсвоитьприсвоитьприсвоитьприсвоитьприсвоитьЭто также верно для последовательностей:
[ Пустые скобки могут использоваться для вставки объектов, построенных по умолчанию, например,push_front( deq )()()вставит два объекта, построенных по умолчаниюstr_pair.
Еслиоператор()()слишком громоздко использовать, например,push_front()мы также можем сказать:
Просто чтобы было совершенно ясно, приведенный выше код не ограничивается стандартными контейнерами, но будет работать со всемистандартными контейнерамис правильной функцией члена. Это всего лишьоператор +=(), которые были ограничены стандартными контейнерами.
Function list_of()
But what if we need to initialize a container? This is where
list_of() comes into play. With list_of()
we can create anonymous lists that automatically converts to
any container:
If we need to initialize a container adapter, we need to help the compiler a
little by calling to_adapter(). As the second example also shows,
we can use a comma-separated
list with list_of() if we add parenthesis around the
entire right hand side. It is worth noticing that the first argument
of list_of() determines the type of the anonymous list.
In case of the stack, the anonymous list consists of
const char* objects which are then converted to
a stack of string objects. The conversion is always
possible as long as the conversion between the stored types is possible.
Обратите внимание, что тип, возвращенныйlist_of()(и его варианты), перегружал операторов сравнения. Это позволяет писать тестовый код. BOOST_CHECK_EQUAL (My_container, list_of(2)(3)(4)(5));
Function map_list_of()
This function is defined for pure convenience when working with
maps. Its usage is simple:
#include <boost/assign/list_of.hpp> // for 'map_list_of()'
#include <boost/assert.hpp>
#include <map>
using namespace std;
using namespace boost::assign; // bring 'map_list_of()' into scope
{
map<int,int> next = map_list_of(1,2)(2,3)(3,4)(4,5)(5,6);
BOOST_ASSERT( next.size() == 5 );
BOOST_ASSERT( next[ 1 ] == 2 );
BOOST_ASSERT( next[ 5 ] == 6 );
// or we can use 'list_of()' by specifying what type
// the list consists of
next = list_of< pair<int,int> >(6,7)(7,8)(8,9);
BOOST_ASSERT( next.size() == 3 );
BOOST_ASSERT( next[ 6 ] == 7 );
BOOST_ASSERT( next[ 8 ] == 9 );
}
The function pair_list_of() may also be used.
Function tuple_list_of()
If you are working with tuples, it might be convenient to use
tuple_list_of():
Единственное требование второго аргумента кrepeat_fun()состоит в том, что это нулевая функция.
Если вам просто нужно вставить итератор-диапазон где-то в списке, функциядиапазонапредоставляет именно то, что вы хотите. Он основан наBoost.Range, поэтому вы можете пройти все диапазоны, поддерживаемые этой библиотекой. Например,
]][0,1,3,1,3,4]]][ Как вы можете видеть, можно также пройти два итератора, если это более целесообразно. Последний пример также содержит список ссылок. Подробнее об этом ниже.
Functions ref_list_of() and cref_list_of()
When you need to create an anonymous range of values and speed is essential,
these two functions provide what you want.
#include <boost/assign/list_of.hpp>#include <algorithm>
//
// Define Range algorithm
//template< class Range >typename Range::const_iterator max_element( const Range& r ){
return std::max_element( r.begin(), r.end() );}
using namespace boost::assign;
{
int a=1,b=5,c=3,d=4,e=2,f=9,g=0,h=7;
int& max = *max_element( ref_list_of<8>(a)(b)(c)(d)(e)(f)(g)(h) );
BOOST_CHECK_EQUAL( max, f );
max = 8;
BOOST_CHECK_EQUAL( f, 8 );
const int& const_max = *max_element(cref_list_of<8>(a)(b)(c)(d)(e)(f)(g)(h) );
BOOST_CHECK_EQUAL( max, const_max );}
You can only use lvalues with ref_list_of() while
cref_list_of() accepts rvalues too. Do not worry about not
specifying exactly the right size; the extra space used is minimal and there
is no runtime overhead associated with it.
You may also use these functions instead of list_of() if speed is
essential.
A "complicated" example
В качестве последнего примера предположим, что нужно следить за результатом футбольных матчей. Команда получит одно очко, если выиграет, и ноль в противном случае. Если бы в каждой группе были сыграны три игры, то код мог бы выглядеть так:
]]][1703 В первом примере обратите внимание, как результатlist_of()может быть автоматически преобразован вvector, посколькувставить()знает, что ожидает вектор. Во втором примере мы видим, чтосписок_of()несколько менее разумен, так как здесь нужно прямо сказать, каких аргументов ожидать. (В будущем можно будет ввести более интеллектуальный уровень преобразования всписок_().)
Functions ptr_push_back(),
ptr_push_front(), ptr_insert() and ptr_map_insert()
For use with Boost.Pointer Container
a few special exception-safe functions are provided. Using these function you
do not need to call new manually:
#include<boost/assign/ptr_list_inserter.hpp>// for 'ptr_push_back()', 'ptr_insert()' and 'ptr_push_front()'#include<boost/assign/ptr_map_inserter.hpp>// for 'ptr_map_insert()'#include<boost/ptr_container/ptr_deque.hpp>#include<boost/ptr_container/ptr_set.hpp>#include<boost/ptr_container/ptr_map.hpp>//
// Example class
//structFoo{inti;Foo():i(0){}Foo(inti):i(i){}Foo(inti,int):i(i){}Foo(constchar*,inti,int):i(i){}virtual~Foo(){}};structBar:Foo{Bar(){}Bar(inti):Foo(42){}};//
// Required by ptr_set<Foo>
//inlinebooloperator<(Fool,Foor){returnl.i<r.i;}usingnamespaceboost;usingnamespaceboost::assign;intmain(){ptr_deque<Foo>deq;ptr_push_back(deq)()();BOOST_ASSERT(deq.size()==2u);ptr_push_back<Bar>(deq)()();// insert 'Bar' objectsBOOST_ASSERT(deq.size()==4u);ptr_push_front(deq)(3)(42,42)("foo",42,42);BOOST_ASSERT(deq.size()==7u);ptr_set<Foo>a_set;ptr_insert(a_set)()(1)(2,2)("foo",3,3);BOOST_ASSERT(a_set.size()==4u);ptr_insert(a_set)()()()();BOOST_ASSERT(a_set.size()==4u);// duplicates not insertedptr_insert<Bar>(a_set)(42);// insert a 'Bar' objectBOOST_ASSERT(a_set.size()==5u);ptr_map<int,Foo>a_map;ptr_map_insert(a_map)(1)(2,2)(3,3,3)(4,"foo",4,4);ptr_map_insert<Bar>(a_map)(42,42);// insert a 'Bar' object}
Notice how you may provide a template argument to these functions. This argument determines the type to allocate with new.
You have to specify this argument when the container is based on an abstract type (because one cannot create objects of such a type).
Дляptr_map_insert()первый аргументarg1в наборе аргументов(arg1,arg2,...,argN)используется для построения ключа; это означает, что первый аргумент должен быть конвертируемым только вkey_typeконтейнера. Остальные аргументы используются для построения отображенного объекта.
Function ptr_list_of()
Just like you can use list_of() to initialize containers, you can
use ptr_list_of() to initialize a pointer container.
Here is a small example:
Notice that a trailing .to_container(deq) may be added to help many poor
compilers to figure out the conversion (a few get it right).
Notice also that pointer maps are
not supported.
Вот и все, теперь вы готовы использовать эту библиотеку.
Стоит отметить, как осуществляется библиотека. Свободно стоящая функция (например,push_back()илиоператор +=())) возвращает прокси-объект, который отвечает за вставку или назначение. Прокси-объект выполняет вставку или назначение посредством перегрузкиоператора,()иоператора()()и вызова функции «вставки» из этих операторов. Функция «вставки» обычно хранится в прокси-объекте с помощью ускорения::функция.
Часто перегрузкаоператора,()не рекомендуется, потому что это может привести к удивительным результатам, но подход, принятый в этой библиотеке, безопасен, поскольку пользователь никогда не имеет дело с объектами, которые перегрузилиоператора,()напрямую. Однако вы должны знать об этом:
Выражения в списке, разделенном запятой, больше не следуют правилам встроенного оператора запятой. Это означает, что порядок оценки выражений в списке, разделенном запятой, не определен, как при определении списка аргументов функции.
Большая часть кода в этом документе используетintв примерах, но, конечно, он работает для произвольных типов, если они являются Copy Constructible. Вставленные данные не обязательно должны быть постоянными данными, но могут быть переменными или данными, возвращенными из функций; единственное требование заключается в том, что тип данных конвертируется в тип, хранящийся в контейнере.
Вся экспедиция осуществляется путем прохождения объектов по ссылкеconst. Первоначально аргументы были переданы по значению (и до сих пор находятся вtuple_list_of()). Следует помнить, что ссылки могут быть переданы с помощью ускорения:ref.
Все поставлено в пространство именповышение:: назначение.
В следующих трех точках (...) будет означать, что реализация определена.оператор +=()возвращает прокси, который пересылает вызовы либоpush_back(),insert(), либоpush()в зависимости от того, какую работу поддерживает контейнер.
Synopsis
list_inserterstackccvvvvvv;][23 Эти две функции используются для построения анонимного списка, который может быть преобразован в любой стандартный контейнер ибустер::массив.Объект, возвращаемый двумя функциями, гарантированно имеет интерфейс, описанный ниже.
Synopsis
namespace boost {namespace assign{
template< class T >
class Implementation-defined{
public:
const_iterator begin() const;
const_iterator end() const;
template< class U >
Implementation-defined& operator,( U u );
// inserts default-constructed object
Implementation-defined& operator()();
template< class U >
Implementation-defined& operator()( U u );
template< class U, class U2 >
Implementation-defined& operator()( U u, U2 u2 );
//
// and similarly up to 5 arguments
//
//
// Convert to a 'Container'. 'Container' must have a constructor
// which takes two iterators.
//
template< class Container >
operator Container() const;
//
// Convert to a container adapter like 'std::stack<>'.
//
Convertible-to-adapterto_adapter() const;
//
//
// Convert to eg. 'boost::array<T,std::size_t>'. If the
// assigned variable is too small,
// a assignment_exception is thrown.
// If the assigned variable it is too big, the rest of the
// values are default-constructed.
//
template< template <class,std::size_t> class Array, class U, std::size_t sz >
operator Array<U,sz>() const;
};//
// Comparison operators. 'op' can be <,>,<=,>=,==,!=
//template<classRange>boolop(constImplementation-defined&,constRange&);template<classRange>boolop(constRange&,constImplementation-defined&);template< class T >
Implementation-definedlist_of();
template< class T >
Implementation-definedlist_of( T t );
template< class T, class U, class U2 >
Implementation-definedlist_of( U u, U2 u2 );
template< class T, class U, class U2, class U3 >
Implementation-definedlist_of( U u, U2 u2, U3 u3 );
template< class T, class U, class U2, class U3, class U4 >
Implementation-definedlist_of( U u, U2 u2, U3 u3, U4 u4 );
template< class T, class U, class U2, class U3, class U4, class U5 >
Implementation-definedlist_of( U u, U2 u2, U3 u3, U4 u4, U5 u5 );
template< class Key, class T >
Implementation-definedmap_list_of( Key k, T t )
{
return list_of< std::pair<Key,T> >()( k, t );
}} // namespace 'assign'} // namespace 'boost'
Functions repeat(),
repeat_fun() and range()
Эти первые две функции существуют как самостоятельные функции, так и функции-члены объекта, возвращаемогоlist_of()иlist_inserter. Свободно стоящие версии используются для создания крючка для оператора,, чтобы мы могли вызывать функции в середине списка запятых. Функции-члены используются, когда нам нужно назвать функции в середине списка скобок. В обоих случаях мы имеем, что
тип возврата всегда является реализацией, определенной для обеих функций,
список аргументовповтора()является(std::size_t,T), и
список аргументовповтора_fun()является(std::size_t,Nullary_function)
.
The function range() only exists as a member function. The following two overloads are provided:
This class is responsible for inserting elements into containers and
it is the key to extending the library to support your favourite class.
Синопсис
namespace boost{namespace assign{
template< Function, Argument = void >
class list_inserter
{
Function fun;
public:
explicit list_inserter( Function fun );
// conversion constructor
template< class Function2, class Arg >
list_inserter( const list_inserter<Function2,Arg>& );
public:
template< class U >
list_inserter& operator,( U u );
template< class U >
list_inserter& operator=( U u );
// calls 'fun()' with default-constructed object
list_inserter& operator()();
template< class U >
list_inserter& operator()( U u );
template< class U, class U2 >
list_inserter& operator()( U u, U2 u2 )
{
//
// if 'Argument' is 'void'
// fun( u, u2 );
// else
// fun( Argument( u, u2 ) );
//
return *this;
}
//
// similarly up to 5 arguments
//
};template< class C >
list_inserter< ... > push_back( C& );
template< class C >
list_inserter< ... > push_front( C& );
template< class C >
list_inserter< ... > insert( C& );
template< class C >
list_inserter< ... > push( C& );} // namespace 'assign'} // namespace 'boost'
Обратите внимание, как аргументы оператору,иоператорупередаются по-разномувесельюв зависимости от типаАргумента. Поэтому, если мы передаем только один шаблонный аргументlist_inserter,мы можем перенаправить «произвольные» списки аргументов функций. Если мы передаем два аргумента шаблонаlist_inserter, мы можем строить типы с помощью «произвольных» конструкторов.
И поскольку ссылка наlist_inserterвозвращается, мы можем объединить список аргументов очень эффективным способом.
Простая «конструкторская» функция дляlist_inserter. Типичное использование этой функции состоит в том, чтобы назвать ее результатомповышения::bind(), который в целом возвращает нечитаемый и странный шаблон класса.
Synopsis
namespace boost {namespace assign{
template< class Function >
list_inserter<Function> make_list_inserter( Function fun )
{
return list_inserter<Function>( fun );
} }}
Customizing argument list sizes
Эта библиотека использует библиотеку препроцессоров для реализации перегруженных версий оператора()()иlist_of(). По умолчанию вы можете назвать эти функции пятью аргументами, но вы также можете настроить это число, определив заголовок из этой библиотеки:
Гарантии исключения библиотекой являются такими же, как и гарантии функции, которая передается. Для стандартных контейнеров это означает, что сильная гарантия предоставляется для одной вставки и что базовая гарантия предоставляется для многих вставок (при условии, что копируемый объект дает базовую гарантию).
Функции могут включать стандартные исключения, такие какstd::bad_alloc. Обратите внимание, однако, что, к сожалению, стандарт не гарантирует отказы в распределении в стандартных контейнерах, о которых будет сообщеноstd::bad_allocили исключения, полученные изstd:: Exception.
Очень просто заставить библиотеку работать с новыми классами. Этот код показывает, как использоватьоператор +с контейнером:
Обратите внимание, что мы передаем второй аргумент шаблонаlist_inserter, поэтому списки аргументов будут использоваться для построения объектаV. В противном случае мы могли бы попытаться вызватьpush_back()аргументамиnвместо одного.
Альтернативным способом было бы использоватьбустер::функцияибустер::бинд()в комбинации. Однако в этом случае нужно помнить, что незаконно брать адрес функции в стандартной библиотеке.
Вызов функции с большим количеством аргументов также может быть очень полезным. Этот небольшой пример показывает, как мы используем эту функциональность:
//
// A class representing emails
//class email{public:
enum address_option
{
check_addr_book,
dont_check_addr_book
};
private:
typedef std::map< std::string,address_option > address_map;
//
// Store list of persons that must be cc'ed
//
mutable address_map cc_list;
//
// This extra function-object will take care of the
// insertion for us. It stores a reference to a
// map and 'operator()()' does the work.
//
struct add_to_map
{
address_map& m;
add_to_map( address_map& m ) : m(m)
{}
void operator()( const std::string& name, address_option ao )
{
m[ name ] = ao;
}
};
public:
//
// This function constructs the appropriate 'list_inserter'.
// Again we could have use 'boost::function', but it is
// trivial to use a function object.
//
// Notice that we do not specify an extra template
// parameter to 'list_inserter'; this means we forward
// all parameters directly to the function without
// calling any constructor.
//
list_inserter< add_to_map >
add_cc( std::string name, address_option ao )
{
//
// Notice how we pass the arguments 'name' and 'ao' to
// the 'list_inserter'.
//
return make_list_inserter( add_to_map( cc_list ) )( name, ao );
}};
//
// Now we can use the class like this:
//email e;e.add_cc( "Mr. Foo", email::dont_check_addr_book )
( "Mr. Bar", email::check_addr_book )
( "Mrs. FooBar", email::check_addr_book );
Библиотека была успешно составлена и протестирована с помощью MVC++ 7.1, GCC 3.2 (под Cygwin) Comeau 4.3.3
Существуют ограничения на платформы, не поддерживающие шаблонные операторы преобразования. Решение состоит в том, чтобы вызвать определенные функции члена на объекте, возвращенномlist_of():
{
using namespace std;
using namespace boost;
using namespace boost::assign;
vector<int>v = list_of(1)(2)(3)(4).to_container( v );
set<int> s = list_of(1)(2)(3)(4).to_container( s );
map<int,int> m = map_list_of(1,2)(2,3).to_container( m );
stack<int> st = list_of(1)(2)(3)(4).to_adapter( st );
queue<int> q = list_of(1)(2)(3)(4).to_adapter( q );
array<int,4> a = list_of(1)(2)(3)(4).to_array( a );}
Обратите внимание, как вы должны предоставить функции с аргументом, чтобы можно было вывести правильный тип возврата.
Некоторые стандартные библиотеки также не работают. Одна проблема заключается в том, чтовставка()может не работать:
Идея создания библиотеки назначения/инициализации не нова. Функциональность этой библиотеки очень напоминает библиотеку инициализации контейнеров STL Леора Золмана, но для достижения своих целей она не полагается на анализ строк.
Библиотека ненавязчива и предъявляет только минимальные требования к своим поддерживаемым классам. Перегрузка оператора запятой иногда рассматривается как плохая практика.. Тем не менее, это было сделано с успехом, например, в Библиотеке вычислений генеративной матрицы и Блице для инициализации матриц (см.).и. Библиотека инициализации перегружает оператора запятой безопасным способом, позволяя функциям свободного стояния возвращать объект, который отвечает за инициализацию. Поэтому требуется явное действие от программиста, чтобы начать использовать перегруженного оператора,.
В последнее время ведутся некоторые дискуссии о совершенствовании языка для поддержки лучшей инициализации (см.)..
Особая благодарность
Леор Золман для нашей многократной дискуссии, которая в итоге привела к этой библиотеке.
Том Бринкман — менеджер по обзорам.
Хоакин Муньос для переносимости vc6/vc7.
Павел Возенилек за его бесчисленные предложения, улучшения и исправления переносимости.
Статья Boost.Assignment Documentation раздела может быть полезна для разработчиков на c++ и boost.
Материалы статей собраны из открытых источников, владелец сайта не претендует на авторство. Там где авторство установить не удалось, материал подаётся без имени автора. В случае если Вы считаете, что Ваши права нарушены, пожалуйста, свяжитесь с владельцем сайта.