1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923 |
- ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
- The Boost Parameter Library
- ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
- |(logo)|__
- .. |(logo)| image:: ../../../../boost.png
- :alt: Boost
- __ ../../../../index.htm
- -------------------------------------
- :Abstract: Use this library to write functions and class templates that can
- accept arguments by name:
- .. parsed-literal::
- new_window(
- "alert"
- , **_width=10**
- , **_titlebar=false**
- );
- smart_ptr<
- Foo
- , **deleter<Deallocate<Foo> >**
- , **copy_policy<DeepCopy>**
- > p(new Foo);
- Since named arguments can be passed in any order, they are especially useful
- when a function or template has more than one parameter with a useful default
- value. The library also supports *deduced* parameters: that is to say,
- parameters whose identity can be deduced from their types.
- .. @jam_prefix.append('''
- project test
- : requirements <include>. <implicit-dependency>/boost//headers ;
- ''')
- .. @example.prepend('''
- #include <boost/parameter.hpp>
- namespace test {
- BOOST_PARAMETER_NAME(title)
- BOOST_PARAMETER_NAME(width)
- BOOST_PARAMETER_NAME(titlebar)
- BOOST_PARAMETER_FUNCTION(
- (int), new_window, tag, (required (title,*)(width,*)(titlebar,*))
- )
- {
- return 0;
- }
- BOOST_PARAMETER_TEMPLATE_KEYWORD(deleter)
- BOOST_PARAMETER_TEMPLATE_KEYWORD(copy_policy)
- template <typename T>
- struct Deallocate
- {
- };
- struct DeepCopy
- {
- };
- namespace parameter = boost::parameter;
- struct Foo
- {
- };
- template <typename T, typename A0, typename A1>
- struct smart_ptr
- {
- smart_ptr(Foo*);
- };
- }
- using namespace test;
- int x =
- ''');
- .. @test('compile')
- -------------------------------------
- :Authors: David Abrahams, Daniel Wallin
- :Contact: dave@boost-consulting.com, daniel@boostpro.com
- :organization: `BoostPro Computing`_
- :date: $Date: 2005/07/17 19:53:01 $
- :copyright: Copyright David Abrahams, Daniel Wallin
- 2005-2009. Distributed under the Boost Software License,
- Version 1.0. (See accompanying file LICENSE_1_0.txt
- or copy at http://www.boost.org/LICENSE_1_0.txt)
- .. _`BoostPro Computing`: http://www.boostpro.com
- .. _concepts: http://www.boost.org/more/generic_programming.html#concept
- -------------------------------------
- [Note: this tutorial does not cover all details of the library. Please see
- also the `reference documentation`__\ ]
- __ reference.html
- .. contents:: **Table of Contents**
- :depth: 2
- .. role:: concept
- :class: concept
- .. role:: vellipsis
- :class: vellipsis
- .. section-numbering::
- -------------------------------------
- ==========
- Motivation
- ==========
- In C++, arguments_ are normally given meaning by their positions with respect
- to a parameter_ list: the first argument passed maps onto the first parameter
- in a function's definition, and so on. That protocol is fine when there is at
- most one parameter with a default value, but when there are even a few useful
- defaults, the positional interface becomes burdensome:
- * .. compound::
- Since an argument's meaning is given by its position, we have to choose an
- (often arbitrary) order for parameters with default values, making some
- combinations of defaults unusable:
- .. parsed-literal::
- window* new_window(
- char const* name
- , **int border_width = default_border_width**
- , bool movable = true
- , bool initially_visible = true
- );
- bool const movability = false;
- window* w = new_window("alert box", movability);
- In the example above we wanted to make an unmoveable window with a default
- ``border_width``, but instead we got a moveable window with a
- ``border_width`` of zero. To get the desired effect, we'd need to write:
- .. parsed-literal::
- window* w = new_window(
- "alert box", **default_border_width**, movability
- );
- * .. compound::
- It can become difficult for readers to understand the meaning of arguments
- at the call site::
- window* w = new_window("alert", 1, true, false);
- Is this window moveable and initially invisible, or unmoveable and
- initially visible? The reader needs to remember the order of arguments to
- be sure.
- * The author of the call may not remember the order of the arguments either,
- leading to hard-to-find bugs.
- .. @ignore(3)
- -------------------------
- Named Function Parameters
- -------------------------
- .. compound::
- This library addresses the problems outlined above by associating each
- parameter name with a keyword object. Now users can identify arguments by
- name, rather than by position:
- .. parsed-literal::
- window* w = new_window(
- "alert box"
- , **movable_=**\ false
- ); // OK!
- .. @ignore()
- ---------------------------
- Deduced Function Parameters
- ---------------------------
- .. compound::
- A **deduced parameter** can be passed in any position *without* supplying
- an explicit parameter name. It's not uncommon for a function to have
- parameters that can be uniquely identified based on the types of arguments
- passed. The ``name`` parameter to ``new_window`` is one such
- example. None of the other arguments, if valid, can reasonably be
- converted to a ``char const*``. With a deduced parameter interface, we
- could pass the window name in *any* argument position without causing
- ambiguity:
- .. parsed-literal::
- window* w = new_window(
- movable_=false
- , **"alert box"**
- ); // OK!
- window* w = new_window(
- **"alert box"**
- , movable_=false
- ); // OK!
- Appropriately used, a deduced parameter interface can free the user of the
- burden of even remembering the formal parameter names.
- .. @ignore()
- --------------------------------
- Class Template Parameter Support
- --------------------------------
- .. compound::
- The reasoning we've given for named and deduced parameter interfaces
- applies equally well to class templates as it does to functions. Using
- the Parameter library, we can create interfaces that allow template
- arguments (in this case ``shared`` and ``Client``) to be explicitly named,
- like this:
- .. parsed-literal::
- smart_ptr<
- **ownership<shared>**
- , **value_type<Client>**
- > p;
- The syntax for passing named template arguments is not quite as natural as
- it is for function arguments (ideally, we'd be able to write
- ``smart_ptr<ownership = shared, …>``). This small syntactic deficiency
- makes deduced parameters an especially big win when used with class
- templates:
- .. parsed-literal::
- // *p and q could be equivalent, given a deduced*
- // *parameter interface.*
- smart_ptr<**shared**, **Client**> p;
- smart_ptr<**Client**, **shared**> q;
- .. @ignore(2)
- ========
- Tutorial
- ========
- This tutorial shows all the basics—how to build both named- and
- deduced-parameter interfaces to function templates and class
- templates—and several more advanced idioms as well.
- ---------------------------
- Parameter-Enabled Functions
- ---------------------------
- In this section we'll show how the Parameter library can be used to
- build an expressive interface to the `Boost Graph library`__\ 's
- |dfs|_ algorithm. [#old_interface]_
- .. Revisit this
- After laying some groundwork and describing the algorithm's abstract
- interface, we'll show you how to build a basic implementation with keyword
- support. Then we'll add support for default arguments and we'll gradually
- refine the implementation with syntax improvements. Finally we'll show
- how to streamline the implementation of named parameter interfaces,
- improve their participation in overload resolution, and optimize their
- runtime efficiency.
- __ ../../../graph/doc/index.html
- .. _dfs: ../../../graph/doc/depth_first_search.html
- .. |dfs| replace:: ``depth_first_search``
- Headers And Namespaces
- ======================
- Most components of the Parameter library are declared in a header named for
- the component. For example, ::
- #include <boost/parameter/keyword.hpp>
- will ensure ``boost::parameter::keyword`` is known to the compiler. There
- is also a combined header, ``boost/parameter.hpp``, that includes most of
- the library's components. For the the rest of this tutorial, unless we
- say otherwise, you can use the rule above to figure out which header to
- ``#include`` to access any given component of the library.
- .. @example.append('''
- using boost::parameter::keyword;
- ''')
- .. @test('compile')
- Also, the examples below will also be written as if the namespace alias ::
- namespace parameter = boost::parameter;
- .. @ignore()
- has been declared: we'll write ``parameter::xxx`` instead of
- ``boost::parameter::xxx``.
- The Abstract Interface to |dfs|
- ===============================
- The Graph library's |dfs| algorithm is a generic function accepting
- from one to four arguments by reference. If all arguments were
- required, its signature might be as follows::
- template <
- typename Graph
- , typename DFSVisitor
- , typename Index
- , typename ColorMap
- >
- void
- depth_first_search(
- Graph const& graph
- , DFSVisitor visitor
- , typename graph_traits<g>::vertex_descriptor root_vertex
- , IndexMap index_map
- , ColorMap& color
- );
- .. @ignore()
- However, most of the parameters have a useful default value,
- as shown in the table below.
- .. _`parameter table`:
- .. _`default expressions`:
- .. table:: ``depth_first_search`` Parameters
- +-----------------+------+-------------------------+------------------------------------+
- | Parameter | Data | Type | Default Value |
- | Name | Flow | | (if any) |
- +=================+======+=========================+====================================+
- | ``graph`` | in | Model of | none - this argument is required. |
- | | | |IncidenceGraph|_ and | |
- | | | |VertexListGraph|_ | |
- +-----------------+------+-------------------------+------------------------------------+
- | ``visitor`` | in | Model of |DFSVisitor|_ | ``boost::dfs_visitor<>()`` |
- +-----------------+------+-------------------------+------------------------------------+
- | ``root_vertex`` | in | ``graph``'s vertex | ``*vertices(graph).first`` |
- | | | descriptor type. | |
- +-----------------+------+-------------------------+------------------------------------+
- | ``index_map`` | in | Model of | ``get(boost::vertex_index,graph)`` |
- | | | |ReadablePropertyMap|_ | |
- | | | with key type := | |
- | | | ``graph``'s vertex | |
- | | | descriptor and value | |
- | | | type an integer type. | |
- +-----------------+------+-------------------------+------------------------------------+
- | ``color_map`` | in / | Model of | a ``boost::iterator_property_map`` |
- | | out | |ReadWritePropertyMap|_ | created from a ``std::vector`` of |
- | | | with key type := | ``default_color_type`` of size |
- | | | ``graph``'s vertex | ``num_vertices(graph)`` and using |
- | | | descriptor type. | ``index_map`` for the index map. |
- +-----------------+------+-------------------------+------------------------------------+
- .. |IncidenceGraph| replace:: :concept:`Incidence Graph`
- .. |VertexListGraph| replace:: :concept:`Vertex List Graph`
- .. |DFSVisitor| replace:: :concept:`DFS Visitor`
- .. |ReadablePropertyMap| replace:: :concept:`Readable Property Map`
- .. |ReadWritePropertyMap| replace:: :concept:`Read/Write Property Map`
- .. _`IncidenceGraph`: ../../../graph/doc/IncidenceGraph.html
- .. _`VertexListGraph`: ../../../graph/doc/VertexListGraph.html
- .. _`DFSVisitor`: ../../../graph/doc/DFSVisitor.html
- .. _`ReadWritePropertyMap`: ../../../property_map/doc/ReadWritePropertyMap.html
- .. _`ReadablePropertyMap`: ../../../property_map/doc/ReadablePropertyMap.html
- Don't be intimidated by the information in the second and third columns
- above. For the purposes of this exercise, you don't need to understand
- them in detail.
- Defining the Keywords
- =====================
- The point of this exercise is to make it possible to call
- ``depth_first_search`` with named arguments, leaving out any
- arguments for which the default is appropriate:
- .. parsed-literal::
- graphs::depth_first_search(g, **color_map_=my_color_map**);
- .. @ignore()
- To make that syntax legal, there needs to be an object called
- “\ ``color_map_``\ ” whose assignment operator can accept a
- ``my_color_map`` argument. In this step we'll create one such
- **keyword object** for each parameter. Each keyword object will be
- identified by a unique **keyword tag type**.
- .. Revisit this
- We're going to define our interface in namespace ``graphs``. Since users
- need access to the keyword objects, but not the tag types, we'll define
- the keyword objects so they're accessible through ``graphs``, and we'll
- hide the tag types away in a nested namespace, ``graphs::tag``. The
- library provides a convenient macro for that purpose.
- We're going to define our interface in namespace ``graphs``. The
- library provides a convenient macro for defining keyword objects::
- #include <boost/parameter/name.hpp>
- namespace graphs {
- BOOST_PARAMETER_NAME(graph) // Note: no semicolon
- BOOST_PARAMETER_NAME(visitor)
- BOOST_PARAMETER_NAME(root_vertex)
- BOOST_PARAMETER_NAME(index_map)
- BOOST_PARAMETER_NAME(color_map)
- }
- .. @test('compile')
- The declaration of the ``graph`` keyword you see here is equivalent to::
- namespace graphs {
- namespace tag {
- // keyword tag type
- struct graph
- {
- typedef boost::parameter::forward_reference qualifier;
- };
- }
- namespace // unnamed
- {
- // A reference to the keyword object
- boost::parameter::keyword<tag::graph> const& _graph
- = boost::parameter::keyword<tag::graph>::instance;
- }
- }
- .. @example.prepend('#include <boost/parameter/keyword.hpp>')
- .. @test('compile')
- It defines a *keyword tag type* named ``tag::graph`` and a *keyword object*
- reference named ``_graph``.
- This “fancy dance” involving an unnamed namespace and references is all done
- to avoid violating the One Definition Rule (ODR) [#odr]_ when the named
- parameter interface is used by function templates that are instantiated in
- multiple translation units (MSVC6.x users see `this note`__).
- __ `Compiler Can't See References In Unnamed Namespace`_
- Writing the Function
- ====================
- Now that we have our keywords defined, the function template definition
- follows a simple pattern using the ``BOOST_PARAMETER_FUNCTION`` macro::
- #include <boost/parameter/preprocessor.hpp>
- namespace graphs {
- BOOST_PARAMETER_FUNCTION(
- (void), // 1. parenthesized return type
- depth_first_search, // 2. name of the function template
- tag, // 3. namespace of tag types
- (required (graph, *) ) // 4. one required parameter, and
- (optional // four optional parameters,
- // with defaults
- (visitor, *, boost::dfs_visitor<>())
- (root_vertex, *, *vertices(graph).first)
- (index_map, *, get(boost::vertex_index,graph))
- (color_map, *,
- default_color_map(num_vertices(graph), index_map)
- )
- )
- )
- {
- // ... body of function goes here...
- // use graph, visitor, index_map, and color_map
- }
- }
- .. @example.prepend('''
- #include <boost/parameter/name.hpp>
- BOOST_PARAMETER_NAME(graph)
- BOOST_PARAMETER_NAME(visitor)
- BOOST_PARAMETER_NAME(in(root_vertex))
- BOOST_PARAMETER_NAME(in(index_map))
- BOOST_PARAMETER_NAME(in_out(color_map))
- namespace boost {
- template <typename T = int>
- struct dfs_visitor
- {
- };
- int vertex_index = 0;
- }
- ''')
- .. @test('compile')
- The arguments to ``BOOST_PARAMETER_FUNCTION`` are:
- 1. The return type of the resulting function template. Parentheses around
- the return type prevent any commas it might contain from confusing the
- preprocessor, and are always required.
- 2. The name of the resulting function template.
- 3. The name of a namespace where we can find tag types whose names match the
- function's parameter names.
- 4. The function signature.
- Function Signatures
- ===================
- Function signatures are described as one or two adjacent parenthesized terms
- (a Boost.Preprocessor_ sequence_) describing the function's parameters in the
- order in which they'd be expected if passed positionally. Any required
- parameters must come first, but the ``(required … )`` clause can be omitted
- when all the parameters are optional.
- .. _Boost.Preprocessor: ../../../preprocessor/doc/index.html
- .. _sequence: http://boost-consulting.com/mplbook/preprocessor.html#sequences
- Required Parameters
- -------------------
- .. compound::
- Required parameters are given first—nested in a ``(required … )``
- clause—as a series of two-element tuples describing each parameter name
- and any requirements on the argument type. In this case there is only a
- single required parameter, so there's just a single tuple:
- .. parsed-literal::
- (required **(graph, \*)** )
- Since ``depth_first_search`` doesn't require any particular type for its
- ``graph`` parameter, we use an asterix to indicate that any type is
- allowed. Required parameters must always precede any optional parameters
- in a signature, but if there are *no* required parameters, the
- ``(required … )`` clause can be omitted entirely.
- .. @example.prepend('''
- #include <boost/parameter.hpp>
- BOOST_PARAMETER_NAME(graph)
- BOOST_PARAMETER_FUNCTION((void), f, tag,
- ''')
- .. @example.append(') {}')
- .. @test('compile')
- Optional Parameters
- -------------------
- .. compound::
- Optional parameters—nested in an ``(optional … )`` clause—are given as a
- series of adjacent *three*\ -element tuples describing the parameter name,
- any requirements on the argument type, *and* and an expression
- representing the parameter's default value:
- .. parsed-literal::
- (optional
- **(visitor, \*, boost::dfs_visitor<>())
- (root_vertex, \*, \*vertices(graph).first)
- (index_map, \*, get(boost::vertex_index,graph))
- (color_map, \*,
- default_color_map(num_vertices(graph), index_map)
- )**
- )
- .. @example.prepend('''
- #include <boost/parameter.hpp>
- namespace boost {
- int vertex_index = 0;
- template <typename T = int>
- struct dfs_visitor
- {
- };
- }
- BOOST_PARAMETER_NAME(graph)
- BOOST_PARAMETER_NAME(visitor)
- BOOST_PARAMETER_NAME(in(root_vertex))
- BOOST_PARAMETER_NAME(in(index_map))
- BOOST_PARAMETER_NAME(in_out(color_map))
- BOOST_PARAMETER_FUNCTION((void), f, tag,
- (required (graph, \*))
- ''')
- .. @example.append(') {}')
- .. @test('compile')
- Handling “In”, “Out”, “Consume / Move-From”, and “Forward” Parameters
- ---------------------------------------------------------------------
- .. compound::
- By default, Boost.Parameter treats all parameters as if they were
- *forward* `parameters`_, which functions would take in by rvalue reference
- and only ``std::forward`` or ``boost::forward`` to other functions. Such
- parameters can be ``const`` lvalues, mutable lvalues, ``const`` rvalues,
- or mutable rvalues. Therefore, the default configuration grants the most
- flexibility to user code. However:
- * Users can configure one or more parameters to be *in* `parameters`_,
- which can fall into the same categories as *forward* `parameters`_ but
- are now passed by ``const`` lvalue reference and so must only be read
- from. Continuing from the previous example, to indicate that
- ``root_vertex`` and ``index_map`` are read-only, we wrap their names
- in ``in(…)``.
- * Users can configure one or more parameters to be either *out*
- `parameters`_, which functions would strictly write to, or *in-out*
- `parameters`_, which functions would both read from and write
- to. Such parameters can only be mutable lvalues. In the example, to
- indicate that ``color_map`` is read-write, we wrap its name in
- ``in_out(…)``. Note that Boost.Parameter sees no functional
- difference between ``out(…)`` and ``in_out(…)``, so you may choose
- whichever makes your interfaces more self-documenting.
- * Users can configure one or more parameters to be *consume* or
- *move-from* `parameters`_, which functions would take in by mutable
- rvalue reference and ``std::move`` or ``boost::move`` as the last
- access step. Such parameters can only be mutable
- rvalues. Boost.Parameter supports wrapping the corresponding names in
- ``consume(…)`` or ``move_from(…)``.
- .. parsed-literal::
- BOOST_PARAMETER_NAME(graph)
- BOOST_PARAMETER_NAME(visitor)
- BOOST_PARAMETER_NAME(**in(root_vertex)**)
- BOOST_PARAMETER_NAME(**in(index_map)**)
- BOOST_PARAMETER_NAME(**in_out(color_map)**)
- In order to see what happens when parameters are bound to arguments that
- violate their category constraints, attempt to compile the |compose_cpp|_
- test program with either the ``LIBS_PARAMETER_TEST_COMPILE_FAILURE_0``
- macro or the ``LIBS_PARAMETER_TEST_COMPILE_FAILURE_1`` macro
- ``#defined``. You should encounter a compiler error caused by a specific
- constraint violation.
- .. @example.prepend('''
- #include <boost/parameter.hpp>
- namespace boost {
- int vertex_index = 0;
- template <typename T = int>
- struct dfs_visitor
- {
- };
- }
- ''')
- .. @example.append('''
- BOOST_PARAMETER_FUNCTION((void), f, tag,
- (required (graph, \*))
- (optional
- (visitor, \*, boost::dfs_visitor<>())
- (root_vertex, \*, \*vertices(graph).first)
- (index_map, \*, get(boost::vertex_index, graph))
- (color_map, \*,
- default_color_map(num_vertices(graph), index_map)
- )
- )
- )
- {
- }
- ''')
- .. @test('compile')
- .. _`parameters`: http://www.modernescpp.com/index.php/c-core-guidelines-how-to-pass-function-parameters
- .. |compose_cpp| replace:: compose.cpp
- .. _compose_cpp: ../../test/compose.cpp
- Positional Arguments
- --------------------
- When arguments are passed positionally (without the use of keywords), they
- will be mapped onto parameters in the order the parameters are given in the
- signature, so for example in this call ::
- graphs::depth_first_search(x, y);
- .. @ignore()
- ``x`` will always be interpreted as a graph and ``y`` will always be
- interpreted as a visitor.
- Default Expression Evaluation
- -----------------------------
- .. compound::
- Note that in our example, the value of the graph parameter is used in the
- default expressions for ``root_vertex``, ``index_map``, and ``color_map``.
- .. parsed-literal::
- (required (**graph**, \*) )
- (optional
- (visitor, \*, boost::dfs_visitor<>())
- (root_vertex, \*, \*vertices(**graph**).first)
- (index_map, \*, get(boost::vertex_index, **graph**))
- (color_map, \*,
- default_color_map(num_vertices(**graph**), index_map)
- )
- )
- .. @ignore()
- A default expression is evaluated in the context of all preceding
- parameters, so you can use any of their values by name.
- .. compound::
- A default expression is never evaluated—or even instantiated—if an actual
- argument is passed for that parameter. We can actually demonstrate that
- with our code so far by replacing the body of ``depth_first_search`` with
- something that prints the arguments:
- .. parsed-literal::
- #include <boost/graph/depth_first_search.hpp> // for dfs_visitor
- BOOST_PARAMETER_FUNCTION(
- (bool), depth_first_search, tag
- *…signature goes here…*
- )
- {
- std::cout << "graph=" << graph;
- std::cout << std::endl;
- std::cout << "visitor=" << visitor;
- std::cout << std::endl;
- std::cout << "root_vertex=" << root_vertex;
- std::cout << std::endl;
- std::cout << "index_map=" << index_map;
- std::cout << std::endl;
- std::cout << "color_map=" << color_map;
- std::cout << std::endl;
- return true;
- }
- #include <boost/core/lightweight_test.hpp>
- int main()
- {
- char const\* g = "1";
- depth_first_search(1, 2, 3, 4, 5);
- depth_first_search(
- g, '2', _color_map = '5',
- _index_map = "4", _root_vertex = "3"
- );
- return boost::report_errors();
- }
- Despite the fact that default expressions such as
- ``vertices(graph).first`` are ill-formed for the given ``graph``
- arguments, both calls will compile, and each one will print exactly the
- same thing.
- .. @example.prepend('''
- #include <boost/parameter.hpp>
- #include <iostream>
- BOOST_PARAMETER_NAME(graph)
- BOOST_PARAMETER_NAME(visitor)
- BOOST_PARAMETER_NAME(root_vertex)
- BOOST_PARAMETER_NAME(index_map)
- BOOST_PARAMETER_NAME(color_map)
- ''')
- .. @example.replace_emphasis('''
- , (required
- (graph, \*)
- (visitor, \*)
- (root_vertex, \*)
- (index_map, \*)
- (color_map, \*)
- )
- ''')
- .. @test('run')
- Signature Matching and Overloading
- ----------------------------------
- In fact, the function signature is so general that any call to
- ``depth_first_search`` with fewer than five arguments will match our function,
- provided we pass *something* for the required ``graph`` parameter. That might
- not seem to be a problem at first; after all, if the arguments don't match the
- requirements imposed by the implementation of ``depth_first_search``, a
- compilation error will occur later, when its body is instantiated.
- There are at least three problems with very general function signatures.
- 1. By the time our ``depth_first_search`` is instantiated, it has been
- selected as the best matching overload. Some other ``depth_first_search``
- overload might've worked had it been chosen instead. By the time we see a
- compilation error, there's no chance to change that decision.
- 2. Even if there are no overloads, error messages generated at instantiation
- time usually expose users to confusing implementation details. For
- example, users might see references to names generated by
- ``BOOST_PARAMETER_FUNCTION`` such as
- ``graphs::detail::depth_first_search_with_named_params`` (or worse—think
- of the kinds of errors you get from your STL implementation when you make
- a mistake). [#ConceptsTS]_
- 3. The problems with exposing such permissive function template signatures
- have been the subject of much discussion, especially in the presence of
- `unqualified calls`__. If all we want is to avoid unintentional
- argument-dependent lookup (ADL), we can isolate ``depth_first_search`` in
- a namespace containing no types [#using]_, but suppose we *want* it to
- found via ADL?
- __ http://www.open-std.org/jtc1/sc22/wg21/docs/lwg-defects.html#225
- It's usually a good idea to prevent functions from being considered for
- overload resolution when the passed argument types aren't appropriate. The
- library already does this when the required ``graph`` parameter is not
- supplied, but we're not likely to see a depth first search that doesn't take a
- graph to operate on. Suppose, instead, that we found a different depth first
- search algorithm that could work on graphs that don't model
- |IncidenceGraph|_? If we just added a simple overload, it would be
- ambiguous::
- // new overload
- BOOST_PARAMETER_FUNCTION((void), depth_first_search, (tag),
- (required (graph,*))( … )
- )
- {
- // new algorithm implementation
- }
- …
- // ambiguous!
- depth_first_search(boost::adjacency_list<>(), 2, "hello");
- .. @ignore()
- Predicate Requirements
- ......................
- We really don't want the compiler to consider the original version of
- ``depth_first_search`` because the ``root_vertex`` argument, ``"hello"``,
- doesn't meet the requirement__ that it match the ``graph`` parameter's vertex
- descriptor type. Instead, this call should just invoke our new overload. To
- take the original ``depth_first_search`` overload out of contention, we first
- encode this requirement as follows:
- __ `parameter table`_
- .. parsed-literal::
- struct vertex_descriptor_predicate
- {
- template <typename T, typename Args>
- struct apply
- : boost::mpl::if_<
- boost::is_convertible<
- T
- , typename boost::graph_traits<
- typename boost::parameter::value_type<
- Args
- , graphs::graph
- >::type
- >::vertex_descriptor
- >
- , boost::mpl::true\_
- , boost::mpl::false\_
- >
- {
- };
- };
- This encoding is an `MPL Binary Metafunction Class`__, a type with a nested
- ``apply`` metafunction that takes in two template arguments. For the first
- template argument, Boost.Parameter will pass in the type on which we will
- impose the requirement. For the second template argument, Boost.Parameter
- will pass in the entire argument pack, making it possible to extract the
- type of each of the other ``depth_first_search`` parameters via the
- ``value_type`` metafunction and the corresponding keyword tag type. The
- result ``type`` of the ``apply`` metafunction will be equivalent to
- ``boost::mpl::true_`` if ``T`` fulfills our requirement as imposed by the
- ``boost::is_convertible`` statement; otherwise, the result will be
- equivalent to ``boost::mpl::false_``.
- __ ../../../mpl/doc/refmanual/metafunction-class.html
- At this point, we can append the name of our metafunction class, in
- parentheses, to the appropriate ``*`` element of the function signature.
- .. parsed-literal::
- (root_vertex
- , \*(**vertex_descriptor_predicate**)
- , \*vertices(graph).first
- )
- .. @ignore()
- Now the original ``depth_first_search`` will only be called when the
- ``root_vertex`` argument can be converted to the graph's vertex descriptor
- type, and our example that *was* ambiguous will smoothly call the new
- overload.
- We can encode the requirements on other arguments using the same concept; only
- the implementation of the nested ``apply`` metafunction needs to be tweaked
- for each argument. There's no space to give a complete description of graph
- library details here, but suffice it to show that the next few metafunction
- classes provide the necessary checks.
- .. parsed-literal::
- struct graph_predicate
- {
- template <typename T, typename Args>
- struct apply
- : boost::mpl::eval_if<
- boost::is_convertible<
- typename boost::graph_traits<T>::traversal_category
- , boost::incidence_graph_tag
- >
- , boost::mpl::if_<
- boost::is_convertible<
- typename boost::graph_traits<T>::traversal_category
- , boost::vertex_list_graph_tag
- >
- , boost::mpl::true\_
- , boost::mpl::false\_
- >
- >
- {
- };
- };
- struct index_map_predicate
- {
- template <typename T, typename Args>
- struct apply
- : boost::mpl::eval_if<
- boost::is_integral<
- typename boost::property_traits<T>::value_type
- >
- , boost::mpl::if_<
- boost::is_same<
- typename boost::property_traits<T>::key_type
- , typename boost::graph_traits<
- typename boost::parameter::value_type<
- Args
- , graphs::graph
- >::type
- >::vertex_descriptor
- >
- , boost::mpl::true\_
- , boost::mpl::false\_
- >
- >
- {
- };
- };
- struct color_map_predicate
- {
- template <typename T, typename Args>
- struct apply
- : boost::mpl::if_<
- boost::is_same<
- typename boost::property_traits<T>::key_type
- , typename boost::graph_traits<
- typename boost::parameter::value_type<
- Args
- , graphs::graph
- >::type
- >::vertex_descriptor
- >
- , boost::mpl::true\_
- , boost::mpl::false\_
- >
- {
- };
- };
- Likewise, computing the default value for the ``color_map`` parameter is no
- trivial matter, so it's best to factor the computation out to a separate
- function template.
- .. parsed-literal::
- template <typename Size, typename IndexMap>
- boost::iterator_property_map<
- std::vector<boost::default_color_type>::iterator
- , IndexMap
- , boost::default_color_type
- , boost::default_color_type&
- >&
- default_color_map(Size num_vertices, IndexMap const& index_map)
- {
- static std::vector<boost::default_color_type> colors(num_vertices);
- static boost::iterator_property_map<
- std::vector<boost::default_color_type>::iterator
- , IndexMap
- , boost::default_color_type
- , boost::default_color_type&
- > m(colors.begin(), index_map);
- return m;
- }
- The signature encloses each predicate metafunction in parentheses *preceded
- by an asterix*, as follows:
- .. parsed-literal::
- BOOST_PARAMETER_FUNCTION((void), depth_first_search, graphs,
- (required
- (graph, \*(**graph_predicate**))
- )
- (optional
- (visitor
- , \* // not easily checkable
- , boost::dfs_visitor<>()
- )
- (root_vertex
- , (**vertex_descriptor_predicate**)
- , \*vertices(graph).first
- )
- (index_map
- , \*(**index_map_predicate**)
- , get(boost::vertex_index, graph)
- )
- (color_map
- , \*(**color_map_predicate**)
- , default_color_map(num_vertices(graph), index_map)
- )
- )
- )
- .. @example.prepend('''
- #include <boost/parameter.hpp>
- #include <boost/graph/adjacency_list.hpp>
- #include <boost/graph/depth_first_search.hpp>
- #include <boost/graph/graph_traits.hpp>
- #include <boost/property_map/property_map.hpp>
- #include <boost/mpl/and.hpp>
- #include <boost/type_traits/is_convertible.hpp>
- #include <boost/type_traits/is_integral.hpp>
- #include <boost/type_traits/is_same.hpp>
- #include <vector>
- #include <utility>
- BOOST_PARAMETER_NAME((_graph, graphs) graph)
- BOOST_PARAMETER_NAME((_visitor, graphs) visitor)
- BOOST_PARAMETER_NAME((_root_vertex, graphs) in(root_vertex))
- BOOST_PARAMETER_NAME((_index_map, graphs) in(index_map))
- BOOST_PARAMETER_NAME((_color_map, graphs) in_out(color_map))
- ''')
- .. @example.append('''
- {
- }
- #include <boost/core/lightweight_test.hpp>
- #include <boost/graph/adjacency_list.hpp>
- #include <utility>
- int main()
- {
- typedef boost::adjacency_list<
- boost::vecS, boost::vecS, boost::directedS
- > G;
- enum {u, v, w, x, y, z, N};
- typedef std::pair<int, int> E;
- E edges[] = {
- E(u, v), E(u, x), E(x, v), E(y, x),
- E(v, y), E(w, y), E(w,z), E(z, z)
- };
- G g(edges, edges + sizeof(edges) / sizeof(E), N);
- depth_first_search(g);
- depth_first_search(g, _root_vertex = static_cast<int>(x));
- return boost::report_errors();
- }
- ''')
- .. @test('run')
- It usually isn't necessary to so completely encode the type requirements on
- arguments to generic functions. However, doing so is worth the effort: your
- code will be more self-documenting and will often provide a better user
- experience. You'll also have an easier transition to the C++20 standard with
- `language support for constraints and concepts`__.
- __ `ConceptsTS`_
- More on Type Requirements
- .........................
- Encoding type requirements onto a function's parameters is essential for
- enabling the function to have deduced parameter interface. Let's revisit the
- ``new_window`` example for a moment:
- .. parsed-literal::
- window\* w = new_window(
- movable_=false
- , "alert box"
- );
- window\* w = new_window(
- "alert box"
- , movable_=false
- );
- .. @ignore()
- The goal this time is to be able to invoke the ``new_window`` function without
- specifying the keywords. For each parameter that has a required type, we can
- enclose that type in parentheses, then *replace* the ``*`` element of the
- parameter signature:
- .. parsed-literal::
- BOOST_PARAMETER_NAME((name\_, keywords) name)
- BOOST_PARAMETER_NAME((movable\_, keywords) movable)
- BOOST_PARAMETER_FUNCTION((window\*), new_window, keywords,
- (deduced
- (required
- (name, *(char const\*)*)
- (movable, *(bool)*)
- )
- )
- )
- {
- // ...
- }
- .. @ignore()
- The following statements will now work and are equivalent to each other as
- well as the previous statements:
- .. parsed-literal::
- window\* w = new_window(false, "alert box");
- window\* w = new_window("alert box", false);
- .. @ignore()
- Deduced Parameters
- ------------------
- To further illustrate deduced parameter support, consider the example of the
- |def|_ function from Boost.Python_. Its signature is roughly as follows:
- .. parsed-literal::
- template <
- typename Function
- , typename KeywordExpression
- , typename CallPolicies
- >
- void def(
- // Required parameters
- char const\* name, Function func
- // Optional, deduced parameters
- , char const\* docstring = ""
- , KeywordExpression keywords = no_keywords()
- , CallPolicies policies = default_call_policies()
- );
- .. @ignore()
- Try not to be too distracted by the use of the term “keywords” in this
- example: although it means something analogous in Boost.Python to what
- it means in the Parameter library, for the purposes of this exercise
- you can think of it as being completely different.
- When calling ``def``, only two arguments are required. The association
- between any additional arguments and their parameters can be determined by the
- types of the arguments actually passed, so the caller is neither required to
- remember argument positions or explicitly specify parameter names for those
- arguments. To generate this interface using ``BOOST_PARAMETER_FUNCTION``, we
- need only enclose the deduced parameters in a ``(deduced …)`` clause, as
- follows:
- .. parsed-literal::
- char const*& blank_char_ptr()
- {
- static char const* larr = "";
- return larr;
- }
- BOOST_PARAMETER_FUNCTION(
- (bool), def, tag,
- (required (name, (char const\*)) (func,\*) ) // nondeduced
- **(deduced**
- (optional
- (docstring, (char const\*), "")
- (keywords
- // see [#is_keyword_expression]_
- , \*(is_keyword_expression<boost::mpl::_>)
- , no_keywords()
- )
- (policies
- , \*(
- boost::mpl::eval_if<
- boost::is_convertible<boost::mpl::_,char const\*>
- , boost::mpl::false\_
- , boost::mpl::if_<
- // see [#is_keyword_expression]_
- is_keyword_expression<boost::mpl::_>
- , boost::mpl::false\_
- , boost::mpl::true\_
- >
- >
- )
- , default_call_policies()
- )
- )
- **)**
- )
- {
- *…*
- }
- .. @example.replace_emphasis('return true;')
- .. @example.prepend('''
- #include <boost/parameter.hpp>
- BOOST_PARAMETER_NAME(name)
- BOOST_PARAMETER_NAME(func)
- BOOST_PARAMETER_NAME(docstring)
- BOOST_PARAMETER_NAME(keywords)
- BOOST_PARAMETER_NAME(policies)
- struct default_call_policies
- {
- };
- struct no_keywords
- {
- };
- struct keywords
- {
- };
- template <typename T>
- struct is_keyword_expression
- : boost::mpl::false_
- {
- };
- template <>
- struct is_keyword_expression<keywords>
- : boost::mpl::true_
- {
- };
- default_call_policies some_policies;
- void f()
- {
- }
- #include <boost/mpl/placeholders.hpp>
- #include <boost/mpl/if.hpp>
- #include <boost/mpl/eval_if.hpp>
- #include <boost/type_traits/is_convertible.hpp>
- ''')
- .. Admonition:: Syntax Note
- A ``(deduced …)`` clause always contains a ``(required …)`` and/or an
- ``(optional …)`` subclause, and must follow any ``(required …)`` or
- ``(optional …)`` clauses indicating nondeduced parameters at the outer
- level.
- With the declaration above, the following two calls are equivalent:
- .. parsed-literal::
- char const\* f_name = "f";
- def(
- f_name
- , &f
- , **some_policies**
- , **"Documentation for f"**
- );
- def(
- f_name
- , &f
- , **"Documentation for f"**
- , **some_policies**
- );
- .. @example.prepend('''
- int main()
- {
- ''')
- If the user wants to pass a ``policies`` argument that was also, for some
- reason, convertible to ``char const*``, she can always specify the parameter
- name explicitly, as follows:
- .. parsed-literal::
- def(
- f_name
- , &f
- , **_policies = some_policies**
- , "Documentation for f"
- );
- .. @example.append('}')
- .. @test('compile', howmany='all')
- The |deduced_cpp|_ and |deduced_dependent_predicate|_ test programs
- demonstrate additional usage of deduced parameter support.
- .. _Boost.Python: ../../../python/doc/index.html
- .. |def| replace:: ``def``
- .. _def: ../../../python/doc/v2/def.html
- .. |deduced_cpp| replace:: deduced.cpp
- .. _deduced_cpp: ../../test/deduced.cpp
- .. |deduced_dependent_predicate| replace:: deduced_dependent_predicate.cpp
- .. _deduced_dependent_predicate: ../../test/deduced_dependent_predicate.cpp
- Parameter-Dependent Return Types
- --------------------------------
- For some algorithms, the return type depends on at least one of the argument
- types. However, there is one gotcha to avoid when encoding this return type
- while using ``BOOST_PARAMETER_FUNCTION`` or other code generation macros. As
- an example, given the following definitions::
- BOOST_PARAMETER_NAME(x)
- BOOST_PARAMETER_NAME(y)
- BOOST_PARAMETER_NAME(z)
- .. @ignore()
- Let our algorithm simply return one of its arguments. If we naïvely implement
- its return type in terms of ``parameter::value_type``::
- BOOST_PARAMETER_FUNCTION(
- (typename parameter::value_type<Args,tag::y>::type), return_y, tag,
- (deduced
- (required
- (x, (std::map<char const*,std::string>))
- (y, (char const*))
- )
- (optional
- (z, (int), 4)
- )
- )
- )
- {
- return y;
- }
- .. @ignore()
- Then using ``return_y`` in any manner other than with positional arguments
- will result in a compiler error::
- std::map<char const*,std::string> k2s;
- assert("foo" == return_y(2, k2s, "foo")); // error!
- .. @ignore()
- The problem is that even though ``y`` is a required parameter,
- ``BOOST_PARAMETER_FUNCTION`` will generate certain overloads for which the
- argument pack type ``Args`` does not actually contain the keyword tag type
- ``tag::y``. The solution is to use SFINAE to preclude generation of those
- overloads. Since ``parameter::value_type`` is a metafunction, our tool for
- the job is ``lazy_enable_if``::
- BOOST_PARAMETER_FUNCTION(
- (
- // Whenever using 'enable_if', 'disable_if', and so on,
- // do not add the 'typename' keyword in front.
- boost::lazy_enable_if<
- typename mpl::has_key<Args,tag::y>::type
- , parameter::value_type<Args,tag::y>
- >
- // Whenever using 'enable_if', 'disable_if', and so on,
- // do not add '::type' here.
- ), return_y, tag,
- (deduced
- (required
- (x, (std::map<char const*,std::string>))
- (y, (char const*))
- )
- (optional
- (z, (int), 4)
- )
- )
- )
- {
- return y;
- }
- .. @ignore()
- For a working demonstration, see |preprocessor_deduced_cpp|_.
- .. |preprocessor_deduced_cpp| replace:: preprocessor_deduced.cpp
- .. _preprocessor_deduced_cpp: ../../test/preprocessor_deduced.cpp
- ----------------------------------
- Parameter-Enabled Member Functions
- ----------------------------------
- The ``BOOST_PARAMETER_MEMBER_FUNCTION`` and
- ``BOOST_PARAMETER_CONST_MEMBER_FUNCTION`` macros accept exactly the same
- arguments as ``BOOST_PARAMETER_FUNCTION``, but are designed to be used within
- the body of a class::
- BOOST_PARAMETER_NAME(arg1)
- BOOST_PARAMETER_NAME(arg2)
- struct callable2
- {
- BOOST_PARAMETER_CONST_MEMBER_FUNCTION(
- (void), call, tag, (required (arg1,(int))(arg2,(int)))
- )
- {
- std::cout << arg1 << ", " << arg2;
- std::cout << std::endl;
- }
- };
- #include <boost/core/lightweight_test.hpp>
- int main()
- {
- callable2 c2;
- callable2 const& c2_const = c2;
- c2_const.call(1, 2);
- return boost::report_errors();
- }
- .. @example.prepend('''
- #include <boost/parameter.hpp>
- #include <iostream>
- using namespace boost::parameter;
- ''')
- .. @test('run')
- These macros don't directly allow a function's interface to be separated from
- its implementation, but you can always forward arguments on to a separate
- implementation function::
- struct callable2
- {
- BOOST_PARAMETER_CONST_MEMBER_FUNCTION(
- (void), call, tag, (required (arg1,(int))(arg2,(int)))
- )
- {
- call_impl(arg1, arg2);
- }
- private:
- void call_impl(int, int); // implemented elsewhere.
- };
- .. @example.prepend('''
- #include <boost/parameter.hpp>
- BOOST_PARAMETER_NAME(arg1)
- BOOST_PARAMETER_NAME(arg2)
- using namespace boost::parameter;
- ''')
- .. @test('compile')
- Static Member Functions
- =======================
- To expose a static member function, simply insert the keyword “``static``”
- before the function name:
- .. parsed-literal::
- BOOST_PARAMETER_NAME(arg1)
- struct somebody
- {
- BOOST_PARAMETER_MEMBER_FUNCTION(
- (void), **static** f, tag, (optional (arg1,(int),0))
- )
- {
- std::cout << arg1 << std::endl;
- }
- };
- #include <boost/core/lightweight_test.hpp>
- int main()
- {
- somebody::f();
- somebody::f(4);
- return boost::report_errors();
- }
- .. @example.prepend('''
- #include <boost/parameter.hpp>
- #include <iostream>
- using namespace boost::parameter;
- ''')
- .. @test('run')
- -----------------------------------------
- Parameter-Enabled Function Call Operators
- -----------------------------------------
- The ``BOOST_PARAMETER_FUNCTION_CALL_OPERATOR`` and
- ``BOOST_PARAMETER_CONST_FUNCTION_CALL_OPERATOR`` macros accept the same
- arguments as the ``BOOST_PARAMETER_MEMBER_FUNCTION`` and
- ``BOOST_PARAMETER_CONST_MEMBER_FUNCTION`` macros except for the function name,
- because these macros allow instances of the enclosing classes to be treated as
- function objects::
- BOOST_PARAMETER_NAME(first_arg)
- BOOST_PARAMETER_NAME(second_arg)
- struct callable2
- {
- BOOST_PARAMETER_CONST_FUNCTION_CALL_OPERATOR(
- (void), tag, (required (first_arg,(int))(second_arg,(int)))
- )
- {
- std::cout << first_arg << ", ";
- std::cout << second_arg << std::endl;
- }
- };
- #include <boost/core/lightweight_test.hpp>
- int main()
- {
- callable2 c2;
- callable2 const& c2_const = c2;
- c2_const(1, 2);
- return boost::report_errors();
- }
- .. @example.prepend('''
- #include <boost/parameter.hpp>
- #include <iostream>
- using namespace boost::parameter;
- ''')
- .. @test('run')
- ------------------------------
- Parameter-Enabled Constructors
- ------------------------------
- The lack of a “delegating constructor” feature in C++
- (http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2006/n1986.pdf)
- limits somewhat the quality of interface this library can provide
- for defining parameter-enabled constructors. The usual workaround
- for a lack of constructor delegation applies: one must factor the
- common logic into one or more base classes.
- Let's build a parameter-enabled constructor that simply prints its
- arguments. The first step is to write a base class whose
- constructor accepts a single argument known as an |ArgumentPack|_:
- a bundle of references to the actual arguments, tagged with their
- keywords. The values of the actual arguments are extracted from
- the |ArgumentPack| by *indexing* it with keyword objects::
- BOOST_PARAMETER_NAME(name)
- BOOST_PARAMETER_NAME(index)
- struct myclass_impl
- {
- template <typename ArgumentPack>
- myclass_impl(ArgumentPack const& args)
- {
- std::cout << "name = " << args[_name];
- std::cout << "; index = " << args[_index | 42];
- std::cout << std::endl;
- }
- };
- .. @example.prepend('''
- #include <boost/parameter.hpp>
- #include <iostream>
- ''')
- Note that the bitwise or (“\ ``|``\ ”) operator has a special meaning when
- applied to keyword objects that are passed to an |ArgumentPack|\ 's indexing
- operator: it is used to indicate a default value. In this case if there is no
- ``index`` parameter in the |ArgumentPack|, ``42`` will be used instead.
- Now we are ready to write the parameter-enabled constructor interface::
- struct myclass : myclass_impl
- {
- BOOST_PARAMETER_CONSTRUCTOR(
- myclass, (myclass_impl), tag
- , (required (name,*)) (optional (index,*))
- ) // no semicolon
- };
- Since we have supplied a default value for ``index`` but not for ``name``,
- only ``name`` is required. We can exercise our new interface as follows::
- myclass x("bob", 3); // positional
- myclass y(_index = 12, _name = "sally"); // named
- myclass z("june"); // positional/defaulted
- .. @example.wrap('''
- #include <boost/core/lightweight_test.hpp>
- int main() {
- ''', ' return boost::report_errors(); }')
- .. @test('run', howmany='all')
- For more on |ArgumentPack| manipulation, see the `Advanced Topics`_ section.
- ---------------------------------
- Parameter-Enabled Class Templates
- ---------------------------------
- In this section we'll use Boost.Parameter to build Boost.Python_\
- 's `class_`_ template, whose “signature” is:
- .. parsed-literal::
- template <
- ValueType, BaseList = bases<>
- , HeldType = ValueType, Copyable = void
- >
- class class\_;
- .. @ignore()
- Only the first argument, ``ValueType``, is required.
- .. _class_: http://www.boost.org/libs/python/doc/v2/class.html#class_-spec
- Named Template Parameters
- =========================
- First, we'll build an interface that allows users to pass arguments
- positionally or by name:
- .. parsed-literal::
- struct B
- {
- virtual ~B() = 0;
- };
-
- struct D : B
- {
- ~D();
- };
- class_<
- **class_type<B>**
- , **copyable<boost::noncopyable>**
- > …;
- class_<
- **D**
- , **held_type<std::auto_ptr<D> >**
- , **base_list<bases<B> >**
- > …;
- .. @ignore()
- Template Keywords
- -----------------
- The first step is to define keywords for each template parameter::
- namespace boost { namespace python {
- BOOST_PARAMETER_TEMPLATE_KEYWORD(class_type)
- BOOST_PARAMETER_TEMPLATE_KEYWORD(base_list)
- BOOST_PARAMETER_TEMPLATE_KEYWORD(held_type)
- BOOST_PARAMETER_TEMPLATE_KEYWORD(copyable)
- }}
- .. @example.prepend('#include <boost/parameter.hpp>')
- .. @test('compile')
- The declaration of the ``class_type`` keyword you see here is equivalent to::
- namespace boost { namespace python {
- namespace tag {
- struct class_type; // keyword tag type
- }
- template <typename T>
- struct class_type
- : parameter::template_keyword<tag::class_type,T>
- {
- };
- }}
- .. @example.prepend('#include <boost/parameter.hpp>')
- .. @test('compile')
- It defines a keyword tag type named ``tag::class_type`` and a
- *parameter passing template* named ``class_type``.
- Class Template Skeleton
- -----------------------
- The next step is to define the skeleton of our class template, which has three
- optional parameters. Because the user may pass arguments in any order, we
- don't know the actual identities of these parameters, so it would be premature
- to use descriptive names or write out the actual default values for any of
- them. Instead, we'll give them generic names and use the special type
- ``boost::parameter::void_`` as a default:
- .. parsed-literal::
- namespace boost { namespace python {
- template <
- typename A0
- , typename A1 = boost::parameter::void\_
- , typename A2 = boost::parameter::void\_
- , typename A3 = boost::parameter::void\_
- >
- struct class\_
- {
- *…*
- };
- }}
- .. @example.prepend('#include <boost/parameter.hpp>')
- .. @example.replace_emphasis('')
- .. @test('compile')
- Class Template Signatures
- -------------------------
- Next, we need to build a type, known as a |ParameterSpec|_, describing the
- “signature” of ``boost::python::class_``. A |ParameterSpec|_ enumerates the
- required and optional parameters in their positional order, along with any
- type requirements (note that it does *not* specify defaults -- those will be
- dealt with separately)::
- namespace boost { namespace python {
- using boost::mpl::_;
- typedef parameter::parameters<
- required<tag::class_type, boost::is_class<_> >
- , parameter::optional<tag::base_list, mpl::is_sequence<_> >
- , parameter::optional<tag::held_type>
- , parameter::optional<tag::copyable>
- > class_signature;
- }}
- .. @example.prepend('''
- #include <boost/parameter.hpp>
- #include <boost/mpl/is_sequence.hpp>
- #include <boost/noncopyable.hpp>
- #include <boost/type_traits/is_class.hpp>
- #include <memory>
- using namespace boost::parameter;
- namespace boost { namespace python {
- BOOST_PARAMETER_TEMPLATE_KEYWORD(class_type)
- BOOST_PARAMETER_TEMPLATE_KEYWORD(base_list)
- BOOST_PARAMETER_TEMPLATE_KEYWORD(held_type)
- BOOST_PARAMETER_TEMPLATE_KEYWORD(copyable)
- template <typename B = int>
- struct bases
- {
- };
- }}
- ''')
- .. |ParameterSpec| replace:: :concept:`ParameterSpec`
- .. _ParameterSpec: reference.html#parameterspec
- .. _binding_intro:
- Argument Packs and Parameter Extraction
- ---------------------------------------
- Next, within the body of ``class_`` , we use the |ParameterSpec|\ 's
- nested ``::bind< … >`` template to bundle the actual arguments into an
- |ArgumentPack|_ type, and then use the library's ``value_type< … >``
- metafunction to extract “logical parameters”. ``value_type< … >`` is
- a lot like ``binding< … >``, but no reference is added to the actual
- argument type. Note that defaults are specified by passing it an
- optional third argument::
- namespace boost { namespace python {
- template <
- typename A0
- , typename A1 = boost::parameter::void_
- , typename A2 = boost::parameter::void_
- , typename A3 = boost::parameter::void_
- >
- struct class_
- {
- // Create ArgumentPack
- typedef typename class_signature::template bind<
- A0, A1, A2, A3
- >::type args;
- // Extract first logical parameter.
- typedef typename parameter::value_type<
- args, tag::class_type
- >::type class_type;
- typedef typename parameter::value_type<
- args, tag::base_list, bases<>
- >::type base_list;
- typedef typename parameter::value_type<
- args, tag::held_type, class_type
- >::type held_type;
- typedef typename parameter::value_type<
- args, tag::copyable, void
- >::type copyable;
- };
- }}
- .. |ArgumentPack| replace:: :concept:`ArgumentPack`
- .. _ArgumentPack: reference.html#argumentpack
- Exercising the Code So Far
- ==========================
- .. compound::
- Revisiting our original examples, ::
- typedef boost::python::class_<
- class_type<B>, copyable<boost::noncopyable>
- > c1;
- typedef boost::python::class_<
- D
- , held_type<std::auto_ptr<D> >
- , base_list<bases<B> >
- > c2;
- .. @example.prepend('''
- using boost::python::class_type;
- using boost::python::copyable;
- using boost::python::held_type;
- using boost::python::base_list;
- using boost::python::bases;
- struct B
- {
- };
- struct D
- {
- };
- ''')
- we can now examine the intended parameters::
- BOOST_MPL_ASSERT((boost::is_same<c1::class_type, B>));
- BOOST_MPL_ASSERT((boost::is_same<c1::base_list, bases<> >));
- BOOST_MPL_ASSERT((boost::is_same<c1::held_type, B>));
- BOOST_MPL_ASSERT((
- boost::is_same<c1::copyable, boost::noncopyable>
- ));
- BOOST_MPL_ASSERT((boost::is_same<c2::class_type, D>));
- BOOST_MPL_ASSERT((boost::is_same<c2::base_list, bases<B> >));
- BOOST_MPL_ASSERT((
- boost::is_same<c2::held_type, std::auto_ptr<D> >
- ));
- BOOST_MPL_ASSERT((boost::is_same<c2::copyable, void>));
- .. @test('compile', howmany='all')
- Deduced Template Parameters
- ===========================
- To apply a deduced parameter interface here, we need only make the type
- requirements a bit tighter so the ``held_type`` and ``copyable`` parameters
- can be crisply distinguished from the others. Boost.Python_ does this by
- requiring that ``base_list`` be a specialization of its ``bases< … >``
- template (as opposed to being any old MPL sequence) and by requiring that
- ``copyable``, if explicitly supplied, be ``boost::noncopyable``. One easy way
- of identifying specializations of ``bases< … >`` is to derive them all from
- the same class, as an implementation detail:
- .. parsed-literal::
- namespace boost { namespace python {
- namespace detail {
- struct bases_base
- {
- };
- }
- template <
- typename A0 = void, typename A1 = void, typename A2 = void *…*
- >
- struct bases **: detail::bases_base**
- {
- };
- }}
- .. @example.replace_emphasis('')
- .. @example.prepend('''
- #include <boost/parameter.hpp>
- #include <boost/mpl/is_sequence.hpp>
- #include <boost/noncopyable.hpp>
- #include <memory>
- using namespace boost::parameter;
- using boost::mpl::_;
- namespace boost { namespace python {
- BOOST_PARAMETER_TEMPLATE_KEYWORD(class_type)
- BOOST_PARAMETER_TEMPLATE_KEYWORD(base_list)
- BOOST_PARAMETER_TEMPLATE_KEYWORD(held_type)
- BOOST_PARAMETER_TEMPLATE_KEYWORD(copyable)
- }}
- ''')
- Now we can rewrite our signature to make all three optional parameters
- deducible::
- typedef parameter::parameters<
- required<tag::class_type, is_class<_> >
- , parameter::optional<
- deduced<tag::base_list>
- , is_base_and_derived<detail::bases_base,_>
- >
- , parameter::optional<
- deduced<tag::held_type>
- , mpl::not_<
- mpl::or_<
- is_base_and_derived<detail::bases_base,_>
- , is_same<noncopyable,_>
- >
- >
- >
- , parameter::optional<
- deduced<tag::copyable>
- , is_same<noncopyable,_>
- >
- > class_signature;
- .. @example.prepend('''
- #include <boost/type_traits/is_class.hpp>
- namespace boost { namespace python {
- ''')
- .. @example.append('''
- template <
- typename A0
- , typename A1 = boost::parameter::void_
- , typename A2 = boost::parameter::void_
- , typename A3 = boost::parameter::void_
- >
- struct class_
- {
- // Create ArgumentPack
- typedef typename class_signature::bind<
- A0, A1, A2, A3
- >::type args;
- // Extract first logical parameter.
- typedef typename parameter::value_type<
- args, tag::class_type
- >::type class_type;
- typedef typename parameter::value_type<
- args, tag::base_list, bases<>
- >::type base_list;
- typedef typename parameter::value_type<
- args, tag::held_type, class_type
- >::type held_type;
- typedef typename parameter::value_type<
- args, tag::copyable, void
- >::type copyable;
- };
- }}
- ''')
- It may seem like we've added a great deal of complexity, but the benefits to
- our users are greater. Our original examples can now be written without
- explicit parameter names:
- .. parsed-literal::
- typedef boost::python::class_<**B**, **boost::noncopyable**> c1;
- typedef boost::python::class_<
- **D**, **std::auto_ptr<D>**, **bases<B>**
- > c2;
- .. @example.prepend('''
- struct B
- {
- };
- struct D
- {
- };
- using boost::python::bases;
- ''')
- .. @example.append('''
- BOOST_MPL_ASSERT((boost::is_same<c1::class_type, B>));
- BOOST_MPL_ASSERT((boost::is_same<c1::base_list, bases<> >));
- BOOST_MPL_ASSERT((boost::is_same<c1::held_type, B>));
- BOOST_MPL_ASSERT((
- boost::is_same<c1::copyable, boost::noncopyable>
- ));
- BOOST_MPL_ASSERT((boost::is_same<c2::class_type, D>));
- BOOST_MPL_ASSERT((boost::is_same<c2::base_list, bases<B> >));
- BOOST_MPL_ASSERT((
- boost::is_same<c2::held_type, std::auto_ptr<D> >
- ));
- BOOST_MPL_ASSERT((boost::is_same<c2::copyable, void>));
- ''')
- .. @test('compile', howmany='all')
- ===============
- Advanced Topics
- ===============
- At this point, you should have a good grasp of the basics. In this section
- we'll cover some more esoteric uses of the library.
- -------------------------
- Fine-Grained Name Control
- -------------------------
- If you don't like the leading-underscore naming convention used to refer to
- keyword objects, or you need the name ``tag`` for something other than the
- keyword type namespace, there's another way to use ``BOOST_PARAMETER_NAME``:
- .. parsed-literal::
- BOOST_PARAMETER_NAME(
- **(**
- *object-name*
- **,** *tag-namespace*
- **)** *parameter-name*
- )
- .. @ignore()
- Here is a usage example:
- .. parsed-literal::
- BOOST_PARAMETER_NAME(
- (
- **pass_foo**, **keywords**
- ) **foo**
- )
- BOOST_PARAMETER_FUNCTION(
- (int), f,
- **keywords**, (required (**foo**, \*))
- )
- {
- return **foo** + 1;
- }
- int x = f(**pass_foo** = 41);
- .. @example.prepend('#include <boost/parameter.hpp>')
- .. @example.append('''
- int main()
- {
- return 0;
- }
- ''')
- .. @test('run')
- Before you use this more verbose form, however, please read the section on
- `best practices for keyword object naming`__.
- __ `Keyword Naming`_
- ----------------------
- More |ArgumentPack|\ s
- ----------------------
- We've already seen |ArgumentPack|\ s when we looked at
- `parameter-enabled constructors`_ and `class templates`__. As you
- might have guessed, |ArgumentPack|\ s actually lie at the heart of
- everything this library does; in this section we'll examine ways to
- build and manipulate them more effectively.
- __ binding_intro_
- Building |ArgumentPack|\ s
- ==========================
- The simplest |ArgumentPack| is the result of assigning into a keyword object::
- BOOST_PARAMETER_NAME(index)
- template <typename ArgumentPack>
- int print_index(ArgumentPack const& args)
- {
- std::cout << "index = " << args[_index];
- std::cout << std::endl;
- return 0;
- }
- int x = print_index(_index = 3); // prints "index = 3"
- .. @example.prepend('''
- #include <boost/parameter.hpp>
- #include <iostream>
- ''')
- Also, |ArgumentPack|\ s can be composed using the comma operator. The extra
- parentheses below are used to prevent the compiler from seeing two separate
- arguments to ``print_name_and_index``::
- BOOST_PARAMETER_NAME(name)
- template <typename ArgumentPack>
- int print_name_and_index(ArgumentPack const& args)
- {
- std::cout << "name = " << args[_name];
- std::cout << "; ";
- return print_index(args);
- }
- int y = print_name_and_index((_index = 3, _name = "jones"));
- The |compose_cpp|_ test program shows more examples of this feature.
- To build an |ArgumentPack| with positional arguments, we can use a
- |ParameterSpec|_. As introduced described in the section on `Class Template
- Signatures`_, a |ParameterSpec| describes the positional order of parameters
- and any associated type requirements. Just as we can build an |ArgumentPack|
- *type* with its nested ``::bind< … >`` template, we can build an
- |ArgumentPack| *object* by invoking its function call operator:
- .. parsed-literal::
- parameter::parameters<
- required<tag::\ name, is_convertible<_,char const*> >
- , optional<tag::\ index, is_convertible<_,int> >
- > spec;
- char const sam[] = "sam";
- int twelve = 12;
- int z0 = print_name_and_index(
- **spec(** sam, twelve **)**
- );
- int z1 = print_name_and_index(
- **spec(** _index=12, _name="sam" **)**
- );
- .. @example.prepend('''
- namespace parameter = boost::parameter;
- using parameter::required;
- using parameter::optional;
- using boost::is_convertible;
- using boost::mpl::_;
- ''')
- .. @example.append('''
- int main()
- {
- return 0;
- }
- ''')
- .. @test('run', howmany='all')
- Extracting Parameter Types
- ==========================
- If we want to know the types of the arguments passed to
- ``print_name_and_index``, we have a couple of options. The
- simplest and least error-prone approach is to forward them to a
- function template and allow *it* to do type deduction::
- BOOST_PARAMETER_NAME(name)
- BOOST_PARAMETER_NAME(index)
- template <typename Name, typename Index>
- int deduce_arg_types_impl(Name&& name, Index&& index)
- {
- // we know the types
- Name&& n2 = boost::forward<Name>(name);
- Index&& i2 = boost::forward<Index>(index);
- return index;
- }
- template <typename ArgumentPack>
- int deduce_arg_types(ArgumentPack const& args)
- {
- return deduce_arg_types_impl(args[_name], args[_index | 42]);
- }
- .. @example.prepend('''
- #include <boost/parameter.hpp>
- ''')
- .. @example.append('''
- #include <boost/core/lightweight_test.hpp>
- int main()
- {
- int a1 = deduce_arg_types((_name = "foo"));
- int a2 = deduce_arg_types((_name = "foo", _index = 3));
- BOOST_TEST_EQ(a1, 42);
- BOOST_TEST_EQ(a2, 3);
- return boost::report_errors();
- }
- ''')
- .. @test('run')
- Occasionally one needs to deduce argument types without an extra layer of
- function call. For example, suppose we wanted to return twice the value of
- the ``index`` parameter? In that case we can use the ``value_type< … >``
- metafunction introduced `earlier`__::
- BOOST_PARAMETER_NAME(index)
- template <typename ArgumentPack>
- typename boost::parameter::value_type<ArgumentPack,tag::index,int>::type
- twice_index(ArgumentPack const& args)
- {
- return 2 * args[_index | 42];
- }
- .. @example.prepend('''
- #include <boost/parameter.hpp>
- ''')
- .. @example.append('''
- #include <boost/core/lightweight_test.hpp>
- int main()
- {
- int six = twice_index(_index = 3);
- BOOST_TEST_EQ(six, 6);
- return boost::report_errors();
- }
- ''')
- .. @test('run', howmany='all')
- Note that if we had used ``binding< … >`` rather than ``value_type< … >``, we
- would end up returning a reference to the temporary created in the ``2 * …``
- expression.
- __ binding_intro_
- Lazy Default Computation
- ========================
- When a default value is expensive to compute, it would be preferable to avoid
- it until we're sure it's absolutely necessary. ``BOOST_PARAMETER_FUNCTION``
- takes care of that problem for us, but when using |ArgumentPack|\ s
- explicitly, we need a tool other than ``operator|``::
- BOOST_PARAMETER_NAME(s1)
- BOOST_PARAMETER_NAME(s2)
- BOOST_PARAMETER_NAME(s3)
- template <typename ArgumentPack>
- std::string f(ArgumentPack const& args)
- {
- std::string const& s1 = args[_s1];
- std::string const& s2 = args[_s2];
- typename parameter::binding<
- ArgumentPack,tag::s3,std::string
- >::type s3 = args[_s3 | (s1 + s2)]; // always constructs s1 + s2
- return s3;
- }
- std::string x = f((
- _s1="hello,", _s2=" world", _s3="hi world"
- ));
- .. @example.prepend('''
- #include <boost/parameter.hpp>
- #include <string>
- namespace parameter = boost::parameter;
- ''')
- .. @example.append('''
- int main()
- {
- return 0;
- }
- ''')
- .. @test('run')
- In the example above, the string ``"hello, world"`` is constructed despite the
- fact that the user passed us a value for ``s3``. To remedy that, we can
- compute the default value *lazily* (that is, only on demand), by using
- ``boost::bind()`` to create a function object.
- .. danielw: I'm leaving the text below in the source, because we might
- .. want to change back to it after 1.34, and if I remove it now we
- .. might forget about it.
- .. by combining the logical-or (“``||``”) operator
- .. with a function object built by the Boost Lambda_ library: [#bind]_
- .. parsed-literal::
- typename parameter::binding<
- ArgumentPack,tag::s3,std::string
- >::type s3 = args[
- _s3 **|| boost::bind(
- std::plus<std::string>(), boost::ref(s1), boost::ref(s2)
- )**
- ];
- .. @example.prepend('''
- #include <boost/bind.hpp>
- #include <boost/ref.hpp>
- #include <boost/parameter.hpp>
- #include <string>
- #include <functional>
- namespace parameter = boost::parameter;
- BOOST_PARAMETER_NAME(s1)
- BOOST_PARAMETER_NAME(s2)
- BOOST_PARAMETER_NAME(s3)
- template <typename ArgumentPack>
- std::string f(ArgumentPack const& args)
- {
- std::string const& s1 = args[_s1];
- std::string const& s2 = args[_s2];
- ''')
- .. @example.append('''
- return s3;
- }
- std::string x = f((_s1="hello,", _s2=" world", _s3="hi world"));
- int main()
- {
- return 0;
- }
- ''')
- .. @test('run')
- .. .. _Lambda: ../../../lambda/index.html
- .. sidebar:: Mnemonics
- To remember the difference between ``|`` and ``||``, recall that ``||``
- normally uses short-circuit evaluation: its second argument is only
- evaluated if its first argument is ``false``. Similarly, in
- ``color_map[param || f]``, ``f`` is only invoked if no ``color_map``
- argument was supplied.
- The expression ``bind(std::plus<std::string>(), ref(s1), ref(s2))`` yields a
- *function object* that, when invoked, adds the two strings together. That
- function will only be invoked if no ``s3`` argument is supplied by the caller.
- .. The expression ``lambda::var(s1) + lambda::var(s2)`` yields a
- .. *function object* that, when invoked, adds the two strings
- .. together. That function will only be invoked if no ``s3`` argument
- .. is supplied by the caller.
- ==============
- Best Practices
- ==============
- By now you should have a fairly good idea of how to use the Parameter
- library. This section points out a few more-marginal issues that will help
- you use the library more effectively.
- --------------
- Keyword Naming
- --------------
- ``BOOST_PARAMETER_NAME`` prepends a leading underscore to the names of all our
- keyword objects in order to avoid the following usually-silent bug:
- .. parsed-literal::
- namespace people
- {
- namespace tag
- {
- struct name
- {
- typedef boost::parameter::forward_reference qualifier;
- };
- struct age
- {
- typedef boost::parameter::forward_reference qualifier;
- };
- }
- namespace // unnamed
- {
- boost::parameter::keyword<tag::name>& **name**
- = boost::parameter::keyword<tag::name>::instance;
- boost::parameter::keyword<tag::age>& **age**
- = boost::parameter::keyword<tag::age>::instance;
- }
- BOOST_PARAMETER_FUNCTION(
- (void), g, tag, (optional (name, \*, "bob")(age, \*, 42))
- )
- {
- std::cout << name << ":" << age;
- }
- void f(int age)
- {
- :vellipsis:`\
- .
- .
- .
- `
- g(**age** = 3); // whoops!
- }
- }
- .. @ignore()
- Although in the case above, the user was trying to pass the value ``3`` as the
- ``age`` parameter to ``g``, what happened instead was that ``f``\ 's ``age``
- argument got reassigned the value 3, and was then passed as a positional
- argument to ``g``. Since ``g``'s first positional parameter is ``name``, the
- default value for ``age`` is used, and g prints ``3:42``. Our leading
- underscore naming convention makes this problem less likely to occur.
- In this particular case, the problem could have been detected if f's ``age``
- parameter had been made ``const``, which is always a good idea whenever
- possible. Finally, we recommend that you use an enclosing namespace for all
- your code, but particularly for names with leading underscores. If we were to
- leave out the ``people`` namespace above, names in the global namespace
- beginning with leading underscores—which are reserved to your C++
- compiler—might become irretrievably ambiguous with those in our
- unnamed namespace.
- ----------
- Namespaces
- ----------
- In our examples we've always declared keyword objects in (an unnamed namespace
- within) the same namespace as the Boost.Parameter-enabled functions using
- those keywords:
- .. parsed-literal::
- namespace lib {
- **BOOST_PARAMETER_NAME(name)
- BOOST_PARAMETER_NAME(index)**
- BOOST_PARAMETER_FUNCTION(
- (int), f, tag,
- (optional (name,*,"bob")(index,(int),1))
- )
- {
- std::cout << name << ":" << index;
- std::cout << std::endl;
- return index;
- }
- }
- .. @example.prepend('''
- #include <boost/parameter.hpp>
- #include <iostream>
- ''')
- .. @namespace_setup = str(example)
- .. @ignore()
- Users of these functions have a few choices:
- 1. Full qualification:
- .. parsed-literal::
- int x = **lib::**\ f(
- **lib::**\ _name = "jill"
- , **lib::**\ _index = 1
- );
- This approach is more verbose than many users would like.
- .. @example.prepend(namespace_setup)
- .. @example.append('int main() { return 0; }')
- .. @test('run')
- 2. Make keyword objects available through *using-declarations*:
- .. parsed-literal::
- **using lib::_name;
- using lib::_index;**
- int x = lib::f(_name = "jill", _index = 1);
- This version is much better at the actual call site, but the
- *using-declarations* themselves can be verbose and hard to manage.
- .. @example.prepend(namespace_setup)
- .. @example.append('int main() { return 0; }')
- .. @test('run')
- 3. Bring in the entire namespace with a *using-directive*:
- .. parsed-literal::
- **using namespace lib;**
- int x = **f**\ (_name = "jill", _index = 3);
- This option is convenient, but it indiscriminately makes the *entire*
- contents of ``lib`` available without qualification.
- .. @example.prepend(namespace_setup)
- .. @example.append('int main() { return 0; }')
- .. @test('run')
- If we add an additional namespace around keyword declarations, though, we can
- give users more control:
- .. parsed-literal::
- namespace lib {
- **namespace keywords {**
- BOOST_PARAMETER_NAME(name)
- BOOST_PARAMETER_NAME(index)
- **}**
- BOOST_PARAMETER_FUNCTION(
- (int), f, **keywords::**\ tag,
- (optional (name,*,"bob")(index,(int),1))
- )
- {
- std::cout << name << ":" << index;
- std::cout << std::endl;
- return index;
- }
- }
- .. @example.prepend('''
- #include <boost/parameter.hpp>
- #include <iostream>
- ''')
- Now users need only a single *using-directive* to bring in just the names of
- all keywords associated with ``lib``:
- .. parsed-literal::
- **using namespace lib::keywords;**
- int y = lib::f(_name = "bob", _index = 2);
- .. @example.append('int main() { return 0; }')
- .. @test('run', howmany='all')
- -------------
- Documentation
- -------------
- The interface idioms enabled by Boost.Parameter are completely new (to C++),
- and as such are not served by pre-existing documentation conventions.
- .. Note:: This space is empty because we haven't settled on any best practices
- yet. We'd be very pleased to link to your documentation if you've got a
- style that you think is worth sharing.
- ==========================
- Portability Considerations
- ==========================
- Use the `regression test results`_ for the latest Boost release of
- the Parameter library to see how it fares on your favorite
- compiler. Additionally, you may need to be aware of the following
- issues and workarounds for particular compilers.
- .. _`regression test results`: http\://www.boost.org/regression/release/user/parameter.html
- --------------------------
- Perfect Forwarding Support
- --------------------------
- If your compiler supports `perfect forwarding`_, then the Parameter library
- will ``#define`` the macro ``BOOST_PARAMETER_HAS_PERFECT_FORWARDING`` unless
- you disable it manually. If your compiler does not provide this support, then
- ``parameter::parameters::operator()`` will treat rvalue references as lvalue
- ``const`` references to work around the `forwarding problem`_, so in certain
- cases you must wrap |boost_ref|_ or |std_ref|_ around any arguments that will
- be bound to out parameters. The |evaluate_category|_ and
- |preprocessor_eval_category|_ test programs demonstrate this support.
- .. _`perfect forwarding`: http\://www.justsoftwaresolutions.co.uk/cplusplus/rvalue_references_and_perfect_forwarding.html
- .. _`forwarding problem`: http\://www.open-std.org/jtc1/sc22/wg21/docs/papers/2002/n1385.htm
- .. |boost_ref| replace:: ``boost::ref``
- .. _boost_ref: ../../../core/doc/html/core/ref.html
- .. |std_ref| replace:: ``std::ref``
- .. _std_ref: http://en.cppreference.com/w/cpp/utility/functional/ref
- .. |evaluate_category| replace:: evaluate_category.cpp
- .. _evaluate_category: ../../test/evaluate_category.cpp
- .. |preprocessor_eval_category| replace:: preprocessor_eval_category.cpp
- .. _preprocessor_eval_category: ../../test/preprocessor_eval_category.cpp
- ------------------
- Boost.MP11 Support
- ------------------
- If your compiler is sufficiently compliant with the C++11 standard, then the
- Parameter library will ``#define`` the macro ``BOOST_PARAMETER_CAN_USE_MP11``
- unless you disable it manually. The |singular_cpp|_, |compose_cpp|_,
- |optional_deduced_sfinae_cpp|_, and |deduced_dep_pred_cpp|_ test programs
- demonstrate support for `Boost.MP11`_.
- .. _`Boost.MP11`: ../../../mp11/doc/html/mp11.html
- .. |singular_cpp| replace:: singular.cpp
- .. _singular_cpp: ../../test/singular.cpp
- .. |optional_deduced_sfinae_cpp| replace:: optional_deduced_sfinae.cpp
- .. _optional_deduced_sfinae_cpp: ../../test/optional_deduced_sfinae.cpp
- .. |deduced_dep_pred_cpp| replace:: deduced_dependent_predicate.cpp
- .. _deduced_dep_pred_cpp: ../../test/deduced_dependent_predicate.cpp
- -----------------
- No SFINAE Support
- -----------------
- Some older compilers don't support SFINAE. If your compiler meets that
- criterion, then Boost headers will ``#define`` the preprocessor symbol
- ``BOOST_NO_SFINAE``, and parameter-enabled functions won't be removed
- from the overload set based on their signatures. The |sfinae_cpp|_ and
- |optional_deduced_sfinae|_ test programs demonstrate SFINAE support.
- .. |sfinae_cpp| replace:: sfinae.cpp
- .. _sfinae_cpp: ../../test/sfinae.cpp
- .. |optional_deduced_sfinae| replace:: optional_deduced_sfinae.cpp
- .. _optional_deduced_sfinae: ../../test/optional_deduced_sfinae.cpp
- ---------------------------
- No Support for |result_of|_
- ---------------------------
- .. |result_of| replace:: ``result_of``
- .. _result_of: ../../../utility/utility.htm#result_of
- `Lazy default computation`_ relies on the |result_of| class template to
- compute the types of default arguments given the type of the function object
- that constructs them. On compilers that don't support |result_of|,
- ``BOOST_NO_RESULT_OF`` will be ``#define``\ d, and the compiler will expect
- the function object to contain a nested type name, ``result_type``, that
- indicates its return type when invoked without arguments. To use an ordinary
- function as a default generator on those compilers, you'll need to wrap it in
- a class that provides ``result_type`` as a ``typedef`` and invokes the
- function via its ``operator()``.
- ..
- Can't Declare |ParameterSpec| via ``typedef``
- =============================================
- In principle you can declare a |ParameterSpec| as a ``typedef`` for a
- specialization of ``parameters<…>``, but Microsoft Visual C++ 6.x has been
- seen to choke on that usage. The workaround is to use inheritance and
- declare your |ParameterSpec| as a class:
- .. parsed-literal::
- **struct dfs_parameters
- :** parameter::parameters<
- tag::graph, tag::visitor, tag::root_vertex
- , tag::index_map, tag::color_map
- >
- **{
- };**
- Default Arguments Unsupported on Nested Templates
- =============================================
- As of this writing, Borland compilers don't support the use of default
- template arguments on member class templates. As a result, you have to
- supply ``BOOST_PARAMETER_MAX_ARITY`` arguments to every use of
- ``parameters<…>::match``. Since the actual defaults used are unspecified,
- the workaround is to use |BOOST_PARAMETER_MATCH|_ to declare default
- arguments for SFINAE.
- .. |BOOST_PARAMETER_MATCH| replace:: ``BOOST_PARAMETER_MATCH``
- --------------------------------------------------
- Compiler Can't See References In Unnamed Namespace
- --------------------------------------------------
- If you use Microsoft Visual C++ 6.x, you may find that the compiler has
- trouble finding your keyword objects. This problem has been observed, but
- only on this one compiler, and it disappeared as the test code evolved, so
- we suggest you use it only as a last resort rather than as a preventative
- measure. The solution is to add *using-declarations* to force the names
- to be available in the enclosing namespace without qualification::
- namespace graphs {
- using graphs::graph;
- using graphs::visitor;
- using graphs::root_vertex;
- using graphs::index_map;
- using graphs::color_map;
- }
- ==============
- Python Binding
- ==============
- .. _python: python.html
- Follow `this link`__ for documentation on how to expose
- Boost.Parameter-enabled functions to Python with `Boost.Python`_.
- __ ../../../parameter_python/doc/html/index.html
- =========
- Reference
- =========
- .. _reference: reference.html
- Follow `this link`__ to the Boost.Parameter reference documentation.
- __ reference.html
- ========
- Glossary
- ========
- .. _arguments:
- -------------------------------
- Argument (or “actual argument”)
- -------------------------------
- the value actually passed to a function or class template.
- .. _parameter:
- ---------------------------------
- Parameter (or “formal parameter”)
- ---------------------------------
- the name used to refer to an argument within a function or class
- template. For example, the value of ``f``'s *parameter* ``x`` is given by the
- *argument* ``3``:
- .. parsed-literal::
- int f(int x) { return x + 1; }
- int y = f(3);
- ================
- Acknowledgements
- ================
- The authors would like to thank all the Boosters who participated in the
- review of this library and its documentation, most especially our review
- manager, Doug Gregor.
- --------------------------
- .. [#old_interface] As of Boost 1.33.0 the Graph library was still using an
- `older named parameter mechanism`__, but there are plans to change it to
- use Boost.Parameter (this library) in an upcoming release, while keeping
- the old interface available for backward-compatibility.
- __ ../../../graph/doc/bgl_named_params.html
- .. [#odr] The **One Definition Rule** says that any given entity in a C++
- program must have the same definition in all translation units (object
- files) that make up a program.
- .. [#vertex_descriptor] If you're not familiar with the Boost Graph Library,
- don't worry about the meaning of any Graph-library-specific details you
- encounter. In this case you could replace all mentions of vertex
- descriptor types with ``int`` in the text, and your understanding of the
- Parameter library wouldn't suffer.
- .. [#ConceptsTS] This is a major motivation behind `C++20 constraints`_.
- .. _`C++20 constraints`: http://en.cppreference.com/w/cpp/language/constraints
- .. .. [#bind] The Lambda library is known not to work on `some
- .. less-conformant compilers`__. When using one of those you could
- .. use `Boost.Bind`_ to generate the function object\:\:
- .. boost\:\:bind(std\:\:plus<std\:\:string>(),s1,s2)
- .. [#is_keyword_expression] Here we're assuming there's a predicate
- metafunction ``is_keyword_expression`` that can be used to identify
- models of Boost.Python's KeywordExpression concept.
- .. .. __ http://www.boost.org/regression/release/user/lambda.html
- .. _Boost.Bind: ../../../bind/index.html
- .. [#using] You can always give the illusion that the function
- lives in an outer namespace by applying a *using-declaration*::
- namespace foo_overloads {
- // foo declarations here
- void foo() { ... }
- ...
- }
- using foo_overloads::foo;
- This technique for avoiding unintentional argument-dependent lookup is due
- to Herb Sutter.
- .. [#sfinae] This capability depends on your compiler's support for
- SFINAE. **SFINAE**: **S**\ ubstitution **F**\ ailure **I**\ s **N**\ ot
- **A**\ n **E**\ rror. If type substitution during the instantiation of a
- function template results in an invalid type, no compilation error is
- emitted; instead the overload is removed from the overload set. By
- producing an invalid type in the function signature depending on the
- result of some condition, we can decide whether or not an overload is
- considered during overload resolution. The technique is formalized in the
- |enable_if|_ utility. Most recent compilers support SFINAE; on compilers
- that don't support it, the Boost config library will ``#define`` the
- symbol ``BOOST_NO_SFINAE``. See
- http://www.semantics.org/once_weakly/w02_SFINAE.pdf for more information
- on SFINAE.
- .. |enable_if| replace:: ``enable_if``
- .. _enable_if: ../../../core/doc/html/core/enable_if.html
|