1[/ 2 / Copyright (c) 2007 Eric Niebler 3 / 4 / Distributed under the Boost Software License, Version 1.0. (See accompanying 5 / file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 6 /] 7 8[/================================================================================] 9[section:back_end Back Ends: 10 Making Expression Templates Do Useful Work] 11[/================================================================================] 12 13Now that you've written the front end for your EDSL compiler, and you've learned a bit about the intermediate form it produces, it's time to think about what to /do/ with the intermediate form. This is where you put your domain-specific algorithms and optimizations. Proto gives you two ways to evaluate and manipulate expression templates: contexts and transforms. 14 15* A /context/ is like a function object that you pass along with an expression to 16 the _eval_ function. It associates behaviors with node types. _eval_ walks the 17 expression and invokes your context at each node. 18* A /transform/ is a way to associate behaviors, not with node types in an 19 expression, but with rules in a Proto grammar. In this way, they are like 20 semantic actions in other compiler-construction toolkits. 21 22Two ways to evaluate expressions! How to choose? Since contexts are largely procedural, they are a bit simpler to understand and debug so they are a good place to start. But although transforms are more advanced, they are also more powerful; since they are associated with rules in your grammar, you can select the proper transform based on the entire /structure/ of a sub-expression rather than simply on the type of its top-most node. 23 24Also, transforms have a concise and declarative syntax that can be confusing at first, but highly expressive and fungible once you become accustomed to it. And -- this is admittedly very subjective -- the author finds programming with Proto transforms to be an inordinate amount of /fun!/ Your mileage may vary. 25 26[/================================================================================] 27[section:expression_evaluation Expression Evaluation: 28 Imparting Behaviors with a Context] 29[/================================================================================] 30 31Once you have constructed a Proto expression tree, either by using Proto's 32operator overloads or with _make_expr_ and friends, you probably want to 33actually /do/ something with it. The simplest option is to use `proto::eval()`, 34a generic expression evaluator. To use _eval_, you'll need to define a 35/context/ that tells _eval_ how each node should be evaluated. This section 36goes through the nuts and bolts of using _eval_, defining evaluation contexts, 37and using the contexts that Proto provides. 38 39[note `proto::eval()` is a less powerful but easier-to-use evaluation technique 40than Proto transforms, which are covered later. Although very powerful, 41transforms have a steep learning curve and can be more difficult to debug. 42`proto::eval()` is a rather weak tree traversal algorithm. Dan Marsden has 43been working on a more general and powerful tree traversal library. When it is 44ready, I anticipate that it will eliminate the need for `proto::eval()`.] 45 46[/================================================================] 47[section:proto_eval Evaluating an Expression with [^proto::eval()]] 48[/================================================================] 49 50[:[*Synopsis:]] 51 52 namespace proto 53 { 54 namespace result_of 55 { 56 // A metafunction for calculating the return 57 // type of proto::eval() given certain Expr 58 // and Context types. 59 template<typename Expr, typename Context> 60 struct eval 61 { 62 typedef 63 typename Context::template eval<Expr>::result_type 64 type; 65 }; 66 } 67 68 namespace functional 69 { 70 // A callable function object type for evaluating 71 // a Proto expression with a certain context. 72 struct eval : callable 73 { 74 template<typename Sig> 75 struct result; 76 77 template<typename Expr, typename Context> 78 typename proto::result_of::eval<Expr, Context>::type 79 operator ()(Expr &expr, Context &context) const; 80 81 template<typename Expr, typename Context> 82 typename proto::result_of::eval<Expr, Context>::type 83 operator ()(Expr &expr, Context const &context) const; 84 }; 85 } 86 87 template<typename Expr, typename Context> 88 typename proto::result_of::eval<Expr, Context>::type 89 eval(Expr &expr, Context &context); 90 91 template<typename Expr, typename Context> 92 typename proto::result_of::eval<Expr, Context>::type 93 eval(Expr &expr, Context const &context); 94 } 95 96Given an expression and an evaluation context, using _eval_ is quite simple. 97Simply pass the expression and the context to _eval_ and it does the rest and 98returns the result. You can use the `eval<>` metafunction in the 99`proto::result_of` namespace to compute the return type of _eval_. The 100following demonstrates a use of _eval_: 101 102 template<typename Expr> 103 typename proto::result_of::eval<Expr const, MyContext>::type 104 MyEvaluate(Expr const &expr) 105 { 106 // Some user-defined context type 107 MyContext ctx; 108 109 // Evaluate an expression with the context 110 return proto::eval(expr, ctx); 111 } 112 113What _eval_ does is also very simple. It defers most of the work to the 114context itself. Here essentially is the implementation of _eval_: 115 116 // eval() dispatches to a nested "eval<>" function 117 // object within the Context: 118 template<typename Expr, typename Context> 119 typename Context::template eval<Expr>::result_type 120 eval(Expr &expr, Context &ctx) 121 { 122 typename Context::template eval<Expr> eval_fun; 123 return eval_fun(expr, ctx); 124 } 125 126Really, _eval_ is nothing more than a thin wrapper that dispatches to the 127appropriate handler within the context class. In the next section, we'll see 128how to implement a context class from scratch. 129 130[endsect] 131 132[/==============================================] 133[section:contexts Defining an Evaluation Context] 134[/==============================================] 135 136As we saw in the previous section, there is really not much to the _eval_ 137function. Rather, all the interesting expression evaluation goes on within 138a context class. This section shows how to implement one from scratch. 139 140All context classes have roughly the following form: 141 142 // A prototypical user-defined context. 143 struct MyContext 144 { 145 // A nested eval<> class template 146 template< 147 typename Expr 148 , typename Tag = typename proto::tag_of<Expr>::type 149 > 150 struct eval; 151 152 // Handle terminal nodes here... 153 template<typename Expr> 154 struct eval<Expr, proto::tag::terminal> 155 { 156 // Must have a nested result_type typedef. 157 typedef ... result_type; 158 159 // Must have a function call operator that takes 160 // an expression and the context. 161 result_type operator()(Expr &expr, MyContext &ctx) const 162 { 163 return ...; 164 } 165 }; 166 167 // ... other specializations of struct eval<> ... 168 }; 169 170Context classes are nothing more than a collection of specializations of a 171nested `eval<>` class template. Each specialization handles a different 172expression type. 173 174In the [link boost_proto.users_guide.getting_started.hello_calculator Hello Calculator] 175section, we saw an example of a user-defined context class for evaluating 176calculator expressions. That context class was implemented with the help 177of Proto's _callable_context_. If we were to implement it from scratch, it 178would look something like this: 179 180 // The calculator_context from the "Hello Calculator" section, 181 // implemented from scratch. 182 struct calculator_context 183 { 184 // The values with which we'll replace the placeholders 185 std::vector<double> args; 186 187 template< 188 typename Expr 189 // defaulted template parameters, so we can 190 // specialize on the expressions that need 191 // special handling. 192 , typename Tag = typename proto::tag_of<Expr>::type 193 , typename Arg0 = typename proto::child_c<Expr, 0>::type 194 > 195 struct eval; 196 197 // Handle placeholder terminals here... 198 template<typename Expr, int I> 199 struct eval<Expr, proto::tag::terminal, placeholder<I> > 200 { 201 typedef double result_type; 202 203 result_type operator()(Expr &, MyContext &ctx) const 204 { 205 return ctx.args[I]; 206 } 207 }; 208 209 // Handle other terminals here... 210 template<typename Expr, typename Arg0> 211 struct eval<Expr, proto::tag::terminal, Arg0> 212 { 213 typedef double result_type; 214 215 result_type operator()(Expr &expr, MyContext &) const 216 { 217 return proto::child(expr); 218 } 219 }; 220 221 // Handle addition here... 222 template<typename Expr, typename Arg0> 223 struct eval<Expr, proto::tag::plus, Arg0> 224 { 225 typedef double result_type; 226 227 result_type operator()(Expr &expr, MyContext &ctx) const 228 { 229 return proto::eval(proto::left(expr), ctx) 230 + proto::eval(proto::right(expr), ctx); 231 } 232 }; 233 234 // ... other eval<> specializations for other node types ... 235 }; 236 237Now we can use _eval_ with the context class above to evaluate calculator 238expressions as follows: 239 240 // Evaluate an expression with a calculator_context 241 calculator_context ctx; 242 ctx.args.push_back(5); 243 ctx.args.push_back(6); 244 double d = proto::eval(_1 + _2, ctx); 245 assert(11 == d); 246 247Defining a context from scratch this way is tedious and verbose, but it gives 248you complete control over how the expression is evaluated. The context class in 249the [link boost_proto.users_guide.getting_started.hello_calculator Hello Calculator] example 250was much simpler. In the next section we'll see the helper class Proto provides 251to ease the job of implementing context classes. 252 253[endsect] 254 255[/================================================] 256[section:canned_contexts Proto's Built-In Contexts] 257[/================================================] 258 259Proto provides some ready-made context classes that you can use as-is, or that 260you can use to help while implementing your own contexts. They are: 261 262[variablelist 263 [ [[link boost_proto.users_guide.back_end.expression_evaluation.canned_contexts.default_context [^default_context]]] 264 [An evaluation context that assigns the usual C++ meanings to all the 265 operators. For example, addition nodes are handled by evaluating the 266 left and right children and then adding the results. The _default_context_ 267 uses Boost.Typeof to deduce the types of the expressions it evaluates.] ] 268 [ [[link boost_proto.users_guide.back_end.expression_evaluation.canned_contexts.null_context [^null_context]]] 269 [A simple context that recursively evaluates children but does not combine 270 the results in any way and returns void.] ] 271 [ [[link boost_proto.users_guide.back_end.expression_evaluation.canned_contexts.callable_context [^callable_context<>]]] 272 [A helper that simplifies the job of writing context classes. Rather than 273 writing template specializations, with _callable_context_ you write a 274 function object with an overloaded function call operator. Any expressions 275 not handled by an overload are automatically dispatched to a default 276 evaluation context that you can specify.] ] 277] 278 279[/=========================================] 280[section:default_context [^default_context]] 281[/=========================================] 282 283The _default_context_ is an evaluation context that assigns the usual C++ 284meanings to all the operators. For example, addition nodes are handled by 285evaluating the left and right children and then adding the results. The 286_default_context_ uses Boost.Typeof to deduce the types of the expressions it 287evaluates. 288 289For example, consider the following "Hello World" example: 290 291 #include <iostream> 292 #include <boost/proto/proto.hpp> 293 #include <boost/proto/context.hpp> 294 #include <boost/typeof/std/ostream.hpp> 295 using namespace boost; 296 297 proto::terminal< std::ostream & >::type cout_ = { std::cout }; 298 299 template< typename Expr > 300 void evaluate( Expr const & expr ) 301 { 302 // Evaluate the expression with default_context, 303 // to give the operators their C++ meanings: 304 proto::default_context ctx; 305 proto::eval(expr, ctx); 306 } 307 308 int main() 309 { 310 evaluate( cout_ << "hello" << ',' << " world" ); 311 return 0; 312 } 313 314This program outputs the following: 315 316[pre 317hello, world 318] 319 320_default_context_ is trivially defined in terms of a `default_eval<>` 321template, as follows: 322 323 // Definition of default_context 324 struct default_context 325 { 326 template<typename Expr> 327 struct eval 328 : default_eval< 329 Expr 330 , default_context const 331 , typename tag_of<Expr>::type 332 > 333 {}; 334 }; 335 336There are a bunch of `default_eval<>` specializations, each of which handles 337a different C++ operator. Here, for instance, is the specialization for binary 338addition: 339 340 // A default expression evaluator for binary addition 341 template<typename Expr, typename Context> 342 struct default_eval<Expr, Context, proto::tag::plus> 343 { 344 private: 345 static Expr & s_expr; 346 static Context & s_ctx; 347 348 public: 349 typedef 350 decltype( 351 proto::eval(proto::child_c<0>(s_expr), s_ctx) 352 + proto::eval(proto::child_c<1>(s_expr), s_ctx) 353 ) 354 result_type; 355 356 result_type operator ()(Expr &expr, Context &ctx) const 357 { 358 return proto::eval(proto::child_c<0>(expr), ctx) 359 + proto::eval(proto::child_c<1>(expr), ctx); 360 } 361 }; 362 363The above code uses `decltype` to calculate the return type of the function 364call operator. `decltype` is a new keyword in the next version of C++ that gets 365the type of any expression. Most compilers do not yet support `decltype` 366directly, so `default_eval<>` uses the Boost.Typeof library to emulate it. On 367some compilers, that may mean that `default_context` either doesn't work or 368that it requires you to register your types with the Boost.Typeof library. 369Check the documentation for Boost.Typeof to see. 370 371[endsect] 372 373[/===================================] 374[section:null_context [^null_context]] 375[/===================================] 376 377The _null_context_ is a simple context that recursively evaluates children 378but does not combine the results in any way and returns void. It is useful 379in conjunction with `callable_context<>`, or when defining your own contexts 380which mutate an expression tree in-place rather than accumulate a result, as 381we'll see below. 382 383_null_context_ is trivially implemented in terms of `null_eval<>` as follows: 384 385 // Definition of null_context 386 struct null_context 387 { 388 template<typename Expr> 389 struct eval 390 : null_eval<Expr, null_context const, Expr::proto_arity::value> 391 {}; 392 }; 393 394And `null_eval<>` is also trivially implemented. Here, for instance is 395a binary `null_eval<>`: 396 397 // Binary null_eval<> 398 template<typename Expr, typename Context> 399 struct null_eval<Expr, Context, 2> 400 { 401 typedef void result_type; 402 403 void operator()(Expr &expr, Context &ctx) const 404 { 405 proto::eval(proto::child_c<0>(expr), ctx); 406 proto::eval(proto::child_c<1>(expr), ctx); 407 } 408 }; 409 410When would such classes be useful? Imagine you have an expression tree with 411integer terminals, and you would like to increment each integer in-place. You 412might define an evaluation context as follows: 413 414 struct increment_ints 415 { 416 // By default, just evaluate all children by delegating 417 // to the null_eval<> 418 template<typename Expr, typename Arg = proto::result_of::child<Expr>::type> 419 struct eval 420 : null_eval<Expr, increment_ints const> 421 {}; 422 423 // Increment integer terminals 424 template<typename Expr> 425 struct eval<Expr, int> 426 { 427 typedef void result_type; 428 429 void operator()(Expr &expr, increment_ints const &) const 430 { 431 ++proto::child(expr); 432 } 433 }; 434 }; 435 436In the next section on _callable_context_, we'll see an even simpler way to 437achieve the same thing. 438 439[endsect] 440 441[/=============================================] 442[section:callable_context [^callable_context<>]] 443[/=============================================] 444 445The _callable_context_ is a helper that simplifies the job of writing context 446classes. Rather than writing template specializations, with _callable_context_ 447you write a function object with an overloaded function call operator. Any 448expressions not handled by an overload are automatically dispatched to a 449default evaluation context that you can specify. 450 451Rather than an evaluation context in its own right, _callable_context_ is more 452properly thought of as a context adaptor. To use it, you must define your own 453context that inherits from _callable_context_. 454 455In the [link boost_proto.users_guide.back_end.expression_evaluation.canned_contexts.null_context [^null_context]] 456section, we saw how to implement an evaluation context that increments all the 457integers within an expression tree. Here is how to do the same thing with the 458_callable_context_: 459 460 // An evaluation context that increments all 461 // integer terminals in-place. 462 struct increment_ints 463 : callable_context< 464 increment_ints const // derived context 465 , null_context const // fall-back context 466 > 467 { 468 typedef void result_type; 469 470 // Handle int terminals here: 471 void operator()(proto::tag::terminal, int &i) const 472 { 473 ++i; 474 } 475 }; 476 477With such a context, we can do the following: 478 479 literal<int> i = 0, j = 10; 480 proto::eval( i - j * 3.14, increment_ints() ); 481 482 std::cout << "i = " << i.get() << std::endl; 483 std::cout << "j = " << j.get() << std::endl; 484 485This program outputs the following, which shows that the integers `i` and `j` 486have been incremented by `1`: 487 488[pre 489i = 1 490j = 11 491] 492 493In the `increment_ints` context, we didn't have to define any nested `eval<>` 494templates. That's because _callable_context_ implements them for us. 495_callable_context_ takes two template parameters: the derived context and a 496fall-back context. For each node in the expression tree being evaluated, 497_callable_context_ checks to see if there is an overloaded `operator()` in the 498derived context that accepts it. Given some expression `expr` of type `Expr`, 499and a context `ctx`, it attempts to call: 500 501 ctx( 502 typename Expr::proto_tag() 503 , proto::child_c<0>(expr) 504 , proto::child_c<1>(expr) 505 ... 506 ); 507 508Using function overloading and metaprogramming tricks, _callable_context_ can 509detect at compile-time whether such a function exists or not. If so, that 510function is called. If not, the current expression is passed to the fall-back 511evaluation context to be processed. 512 513We saw another example of the _callable_context_ when we looked at the simple 514calculator expression evaluator. There, we wanted to customize the evaluation 515of placeholder terminals, and delegate the handling of all other nodes to the 516_default_context_. We did that as follows: 517 518 // An evaluation context for calculator expressions that 519 // explicitly handles placeholder terminals, but defers the 520 // processing of all other nodes to the default_context. 521 struct calculator_context 522 : proto::callable_context< calculator_context const > 523 { 524 std::vector<double> args; 525 526 // Define the result type of the calculator. 527 typedef double result_type; 528 529 // Handle the placeholders: 530 template<int I> 531 double operator()(proto::tag::terminal, placeholder<I>) const 532 { 533 return this->args[I]; 534 } 535 }; 536 537In this case, we didn't specify a fall-back context. In that case, 538_callable_context_ uses the _default_context_. With the above 539`calculator_context` and a couple of appropriately defined placeholder 540terminals, we can evaluate calculator expressions, as demonstrated 541below: 542 543 template<int I> 544 struct placeholder 545 {}; 546 547 terminal<placeholder<0> >::type const _1 = {{}}; 548 terminal<placeholder<1> >::type const _2 = {{}}; 549 // ... 550 551 calculator_context ctx; 552 ctx.args.push_back(4); 553 ctx.args.push_back(5); 554 555 double j = proto::eval( (_2 - _1) / _2 * 100, ctx ); 556 std::cout << "j = " << j << std::endl; 557 558The above code displays the following: 559 560[pre 561j = 20 562] 563 564[endsect] 565 566[endsect] 567 568[endsect] 569 570[import ../test/examples.cpp] 571 572[/============================================================================] 573[section:expression_transformation Expression Transformation: Semantic Actions] 574[/============================================================================] 575 576If you have ever built a parser with the help of a tool like Antlr, yacc or Boost.Spirit, you might be familiar with /semantic actions/. In addition to allowing you to define the grammar of the language recognized by the parser, these tools let you embed code within your grammar that executes when parts of the grammar participate in a parse. Proto has the equivalent of semantic actions. They are called /transforms/. This section describes how to embed transforms within your Proto grammars, turning your grammars into function objects that can manipulate or evaluate expressions in powerful ways. 577 578Proto transforms are an advanced topic. We'll take it slow, using examples to illustrate the key concepts, starting simple. 579 580[/==================================] 581[section ["Activating] Your Grammars] 582[/==================================] 583 584The Proto grammars we've seen so far are static. You can check at compile-time to see if an expression type matches a grammar, but that's it. Things get more interesting when you give them runtime behaviors. A grammar with embedded transforms is more than just a static grammar. It is a function object that accepts expressions that match the grammar and does /something/ with them. 585 586Below is a very simple grammar. It matches terminal expressions. 587 588 // A simple Proto grammar that matches all terminals 589 proto::terminal< _ > 590 591Here is the same grammar with a transform that extracts the value from the terminal: 592 593 // A simple Proto grammar that matches all terminals 594 // *and* a function object that extracts the value from 595 // the terminal 596 proto::when< 597 proto::terminal< _ > 598 , proto::_value // <-- Look, a transform! 599 > 600 601You can read this as follows: when you match a terminal expression, extract the value. The type `proto::_value` is a so-called transform. Later we'll see what makes it a transform, but for now just think of it as a kind of function object. Note the use of _when_: the first template parameter is the grammar to match and the second is the transform to execute. The result is both a grammar that matches terminal expressions and a function object that accepts terminal expressions and extracts their values. 602 603As with ordinary grammars, we can define an empty struct that inherits from a grammar+transform to give us an easy way to refer back to the thing we're defining, as follows: 604 605 // A grammar and a function object, as before 606 struct Value 607 : proto::when< 608 proto::terminal< _ > 609 , proto::_value 610 > 611 {}; 612 613 // "Value" is a grammar that matches terminal expressions 614 BOOST_MPL_ASSERT(( proto::matches< proto::terminal<int>::type, Value > )); 615 616 // "Value" also defines a function object that accepts terminals 617 // and extracts their value. 618 proto::terminal<int>::type answer = {42}; 619 Value get_value; 620 int i = get_value( answer ); 621 622As already mentioned, `Value` is a grammar that matches terminal expressions and a function object that operates on terminal expressions. It would be an error to pass a non-terminal expression to the `Value` function object. This is a general property of grammars with transforms; when using them as function objects, expressions passed to them must match the grammar. 623 624Proto grammars are valid TR1-style function objects. That means you can use `boost::result_of<>` to ask a grammar what its return type will be, given a particular expression type. For instance, we can access the `Value` grammar's return type as follows: 625 626 // We can use boost::result_of<> to get the return type 627 // of a Proto grammar. 628 typedef 629 typename boost::result_of<Value(proto::terminal<int>::type)>::type 630 result_type; 631 632 // Check that we got the type we expected 633 BOOST_MPL_ASSERT(( boost::is_same<result_type, int> )); 634 635[note A grammar with embedded transforms is both a grammar and a function object. Calling these things "grammars with transforms" would get tedious. We could call them something like "active grammars", but as we'll see /every/ grammar that you can define with Proto is "active"; that is, every grammar has some behavior when used as a function object. So we'll continue calling these things plain "grammars". The term "transform" is reserved for the thing that is used as the second parameter to the _when_ template.] 636 637[endsect] 638 639[/=========================================] 640[section Handling Alternation and Recursion] 641[/=========================================] 642 643Most grammars are a little more complicated than the one in the preceding section. For the sake of illustration, let's define a rather nonsensical grammar that matches any expression and recurses to the leftmost terminal and returns its value. It will demonstrate how two key concepts of Proto grammars -- alternation and recursion -- interact with transforms. The grammar is described below. 644 645 // A grammar that matches any expression, and a function object 646 // that returns the value of the leftmost terminal. 647 struct LeftmostLeaf 648 : proto::or_< 649 // If the expression is a terminal, return its value 650 proto::when< 651 proto::terminal< _ > 652 , proto::_value 653 > 654 // Otherwise, it is a non-terminal. Return the result 655 // of invoking LeftmostLeaf on the 0th (leftmost) child. 656 , proto::when< 657 _ 658 , LeftmostLeaf( proto::_child0 ) 659 > 660 > 661 {}; 662 663 // A Proto terminal wrapping std::cout 664 proto::terminal< std::ostream & >::type cout_ = { std::cout }; 665 666 // Create an expression and use LeftmostLeaf to extract the 667 // value of the leftmost terminal, which will be std::cout. 668 std::ostream & sout = LeftmostLeaf()( cout_ << "the answer: " << 42 << '\n' ); 669 670We've seen `proto::or_<>` before. Here it is serving two roles. First, it is a grammar that matches any of its alternate sub-grammars; in this case, either a terminal or a non-terminal. Second, it is also a function object that accepts an expression, finds the alternate sub-grammar that matches the expression, and applies its transform. And since `LeftmostLeaf` inherits from `proto::or_<>`, `LeftmostLeaf` is also both a grammar and a function object. 671 672[def _some_transform_ [~some-transform]] 673 674[note The second alternate uses `proto::_` as its grammar. Recall that `proto::_` is the wildcard grammar that matches any expression. Since alternates in `proto::or_<>` are tried in order, and since the first alternate handles all terminals, the second alternate handles all (and only) non-terminals. Often enough, `proto::when< _, _some_transform_ >` is the last alternate in a grammar, so for improved readability, you could use the equivalent `proto::otherwise< _some_transform_ >`.] 675 676The next section describes this grammar further. 677 678[endsect] 679 680[/==========================] 681[section Callable Transforms] 682[/==========================] 683 684[def __bold_transform__ [*LeftmostLeaf( proto::_child0 )]] 685 686In the grammar defined in the preceding section, the transform associated with non-terminals is a little strange-looking: 687 688 proto::when< 689 _ 690 , __bold_transform__ // <-- a "callable" transform 691 > 692 693It has the effect of accepting non-terminal expressions, taking the 0th (leftmost) child and recursively invoking the `LeftmostLeaf` function on it. But `LeftmostLeaf( proto::_child0 )` is actually a /function type/. Literally, it is the type of a function that accepts an object of type `proto::_child0` and returns an object of type `LeftmostLeaf`. So how do we make sense of this transform? Clearly, there is no function that actually has this signature, nor would such a function be useful. The key is in understanding how `proto::when<>` /interprets/ its second template parameter. 694 695When the second template parameter to _when_ is a function type, _when_ interprets the function type as a transform. In this case, `LeftmostLeaf` is treated as the type of a function object to invoke, and `proto::_child0` is treated as a transform. First, `proto::_child0` is applied to the current expression (the non-terminal that matched this alternate sub-grammar), and the result (the 0th child) is passed as an argument to `LeftmostLeaf`. 696 697[note *Transforms are a Domain-Specific Language* 698 699`LeftmostLeaf( proto::_child0 )` /looks/ like an invocation of the `LeftmostLeaf` function object, but it's not, but then it actually is! Why this confusing subterfuge? Function types give us a natural and concise syntax for composing more complicated transforms from simpler ones. The fact that the syntax is suggestive of a function invocation is on purpose. It is an embedded domain-specific language for defining expression transformations. If the subterfuge worked, it may have fooled you into thinking the transform is doing exactly what it actually does! And that's the point.] 700 701The type `LeftmostLeaf( proto::_child0 )` is an example of a /callable transform/. It is a function type that represents a function object to call and its arguments. The types `proto::_child0` and `proto::_value` are /primitive transforms/. They are plain structs, not unlike function objects, from which callable transforms can be composed. There is one other type of transform, /object transforms/, that we'll encounter next. 702 703[endsect] 704 705[/========================] 706[section Object Transforms] 707[/========================] 708 709The very first transform we looked at simply extracted the value of terminals. Let's do the same thing, but this time we'll promote all ints to longs first. (Please forgive the contrived-ness of the examples so far; they get more interesting later.) Here's the grammar: 710 711 // A simple Proto grammar that matches all terminals, 712 // and a function object that extracts the value from 713 // the terminal, promoting ints to longs: 714 struct ValueWithPomote 715 : proto::or_< 716 proto::when< 717 proto::terminal< int > 718 , long(proto::_value) // <-- an "object" transform 719 > 720 , proto::when< 721 proto::terminal< _ > 722 , proto::_value 723 > 724 > 725 {}; 726 727You can read the above grammar as follows: when you match an int terminal, extract the value from the terminal and use it to initialize a long; otherwise, when you match another kind of terminal, just extract the value. The type `long(proto::_value)` is a so-called /object/ transform. It looks like the creation of a temporary long, but it's really a function type. Just as a callable transform is a function type that represents a function to call and its arguments, an object transforms is a function type that represents an object to construct and the arguments to its constructor. 728 729[/================================================] 730[note *Object Transforms vs. Callable Transforms* 731 732When using function types as Proto transforms, they can either represent an object to construct or a function to call. It is similar to "normal" C++ where the syntax `foo("arg")` can either be interpreted as an object to construct or a function to call, depending on whether `foo` is a type or a function. But consider two of the transforms we've seen so far: 733 734`` 735 LeftmostLeaf(proto::_child0) // <-- a callable transform 736 long(proto::_value) // <-- an object transform 737`` 738 739Proto can't know in general which is which, so it uses a trait, `proto::is_callable<>`, to differentiate. `is_callable< long >::value` is false so `long(proto::_value)` is an object to construct, but `is_callable< LeftmostLeaf >::value` is true so `LeftmostLeaf(proto::_child0)` is a function to call. Later on, we'll see how Proto recognizes a type as "callable".] 740[/================================================] 741 742[endsect] 743 744[/================================] 745[section Example: Calculator Arity] 746[/================================] 747 748Now that we have the basics of Proto transforms down, let's consider a slightly more realistic example. We can use transforms to improve the type-safety of the [link boost_proto.users_guide.getting_started.hello_calculator calculator EDSL]. If you recall, it lets you write infix arithmetic expressions involving argument placeholders like `_1` and `_2` and pass them to STL algorithms as function objects, as follows: 749 750 double a1[4] = { 56, 84, 37, 69 }; 751 double a2[4] = { 65, 120, 60, 70 }; 752 double a3[4] = { 0 }; 753 754 // Use std::transform() and a calculator expression 755 // to calculate percentages given two input sequences: 756 std::transform(a1, a1+4, a2, a3, (_2 - _1) / _2 * 100); 757 758This works because we gave calculator expressions an `operator()` that evaluates the expression, replacing the placeholders with the arguments to `operator()`. The overloaded `calculator<>::operator()` looked like this: 759 760 // Overload operator() to invoke proto::eval() with 761 // our calculator_context. 762 template<typename Expr> 763 double 764 calculator<Expr>::operator()(double a1 = 0, double a2 = 0) const 765 { 766 calculator_context ctx; 767 ctx.args.push_back(a1); 768 ctx.args.push_back(a2); 769 770 return proto::eval(*this, ctx); 771 } 772 773Although this works, it's not ideal because it doesn't warn users if they supply too many or too few arguments to a calculator expression. Consider the following mistakes: 774 775 (_1 * _1)(4, 2); // Oops, too many arguments! 776 (_2 * _2)(42); // Oops, too few arguments! 777 778The expression `_1 * _1` defines a unary calculator expression; it takes one argument and squares it. If we pass more than one argument, the extra arguments will be silently ignored, which might be surprising to users. The next expression, `_2 * _2` defines a binary calculator expression; it takes two arguments, ignores the first and squares the second. If we only pass one argument, the code silently fills in `0.0` for the second argument, which is also probably not what users expect. What can be done? 779 780We can say that the /arity/ of a calculator expression is the number of arguments it expects, and it is equal to the largest placeholder in the expression. So, the arity of `_1 * _1` is one, and the arity of `_2 * _2` is two. We can increase the type-safety of our calculator EDSL by making sure the arity of an expression equals the actual number of arguments supplied. Computing the arity of an expression is simple with the help of Proto transforms. 781 782It's straightforward to describe in words how the arity of an expression should 783be calculated. Consider that calculator expressions can be made of `_1`, `_2`, literals, unary expressions and binary expressions. The following table shows the arities for each of these 5 constituents. 784 785[table Calculator Sub-Expression Arities 786 [[Sub-Expression] [Arity]] 787 [[Placeholder 1] [`1`]] 788 [[Placeholder 2] [`2`]] 789 [[Literal] [`0`]] 790 [[Unary Expression] [ /arity of the operand/ ]] 791 [[Binary Expression] [ /max arity of the two operands/ ]] 792] 793 794Using this information, we can write the grammar for calculator expressions and attach transforms for computing the arity of each constituent. The code below computes the expression arity as a compile-time integer, using integral wrappers and metafunctions from the Boost MPL Library. The grammar is described below. 795 796[CalcArity] 797 798When we find a placeholder terminal or a literal, we use an /object transform/ such as `mpl::int_<1>()` to create a (default-constructed) compile-time integer representing the arity of that terminal. 799 800For unary expressions, we use `CalcArity(proto::_child)` which is a /callable transform/ that computes the arity of the expression's child. 801 802The transform for binary expressions has a few new tricks. Let's look more closely: 803 804 // Compute the left and right arities and 805 // take the larger of the two. 806 mpl::max<CalcArity(proto::_left), 807 CalcArity(proto::_right)>() 808 809This is an object transform; it default-constructs ... what exactly? The `mpl::max<>` template is an MPL metafunction that accepts two compile-time integers. It has a nested `::type` typedef (not shown) that is the maximum of the two. But here, we appear to be passing it two things that are /not/ compile-time integers; they're Proto callable transforms. Proto is smart enough to recognize that fact. It first evaluates the two nested callable transforms, computing the arities of the left and right child expressions. Then it puts the resulting integers into `mpl::max<>` and evaluates the metafunction by asking for the nested `::type`. That is the type of the object that gets default-constructed and returned. 810 811More generally, when evaluating object transforms, Proto looks at the object type and checks whether it is a template specialization, like `mpl::max<>`. If it is, Proto looks for nested transforms that it can evaluate. After any nested transforms have been evaluated and substituted back into the template, the new template specialization is the result type, unless that type has a nested `::type`, in which case that becomes the result. 812 813Now that we can calculate the arity of a calculator expression, let's redefine the `calculator<>` expression wrapper we wrote in the Getting Started guide to use the `CalcArity` grammar and some macros from Boost.MPL to issue compile-time errors when users specify too many or too few arguments. 814 815 // The calculator expression wrapper, as defined in the Hello 816 // Calculator example in the Getting Started guide. It behaves 817 // just like the expression it wraps, but with extra operator() 818 // member functions that evaluate the expression. 819 // NEW: Use the CalcArity grammar to ensure that the correct 820 // number of arguments are supplied. 821 template<typename Expr> 822 struct calculator 823 : proto::extends<Expr, calculator<Expr>, calculator_domain> 824 { 825 typedef 826 proto::extends<Expr, calculator<Expr>, calculator_domain> 827 base_type; 828 829 calculator(Expr const &expr = Expr()) 830 : base_type(expr) 831 {} 832 833 typedef double result_type; 834 835 // Use CalcArity to compute the arity of Expr: 836 static int const arity = boost::result_of<CalcArity(Expr)>::type::value; 837 838 double operator()() const 839 { 840 BOOST_MPL_ASSERT_RELATION(0, ==, arity); 841 calculator_context ctx; 842 return proto::eval(*this, ctx); 843 } 844 845 double operator()(double a1) const 846 { 847 BOOST_MPL_ASSERT_RELATION(1, ==, arity); 848 calculator_context ctx; 849 ctx.args.push_back(a1); 850 return proto::eval(*this, ctx); 851 } 852 853 double operator()(double a1, double a2) const 854 { 855 BOOST_MPL_ASSERT_RELATION(2, ==, arity); 856 calculator_context ctx; 857 ctx.args.push_back(a1); 858 ctx.args.push_back(a2); 859 return proto::eval(*this, ctx); 860 } 861 }; 862 863Note the use of `boost::result_of<>` to access the return type of the `CalcArity` function object. Since we used compile-time integers in our transforms, the arity of the expression is encoded in the return type of the `CalcArity` function object. Proto grammars are valid TR1-style function objects, so you can use `boost::result_of<>` to figure out their return types. 864 865With our compile-time assertions in place, when users provide too many or too few arguments to a calculator expression, as in: 866 867 (_2 * _2)(42); // Oops, too few arguments! 868 869... they will get a compile-time error message on the line with the assertion that reads something like this[footnote This error message was generated with Microsoft Visual C++ 9.0. Different compilers will emit different messages with varying degrees of readability.]: 870 871[pre 872c:\boost\org\trunk\libs\proto\scratch\main.cpp(97) : error C2664: 'boost::mpl::asse 873rtion\_failed' : cannot convert parameter 1 from 'boost::mpl::failed \*\*\*\*\*\*\*\*\*\*\*\*boo 874st::mpl::assert\_relation<x,y,\_\_formal>::\*\*\*\*\*\*\*\*\*\*\*\*' to 'boost::mpl::assert<false> 875::type' 876 with 877 \[ 878 x\=1, 879 y\=2, 880 \_\_formal\=bool boost::mpl::operator\=\=(boost::mpl::failed,boost::mpl::failed) 881 \] 882] 883 884The point of this exercise was to show that we can write a fairly simple Proto grammar with embedded transforms that is declarative and readable and can compute interesting properties of arbitrarily complicated expressions. But transforms can do more than that. Boost.Xpressive uses transforms to turn expressions into finite state automata for matching regular expressions, and Boost.Spirit uses transforms to build recursive descent parser generators. Proto comes with a collection of built-in transforms that you can use to perform very sophisticated expression manipulations like these. In the next few sections we'll see some of them in action. 885 886[endsect] 887 888[/===============================================] 889[section:state Transforms With State Accumulation] 890[/===============================================] 891 892So far, we've only seen examples of grammars with transforms that accept one argument: the expression to transform. But consider for a moment how, in ordinary procedural code, you would turn a binary tree into a linked list. You would start with an empty list. Then, you would recursively convert the right branch to a list, and use the result as the initial state while converting the left branch to a list. That is, you would need a function that takes two parameters: the current node and the list so far. These sorts of /accumulation/ problems are quite common when processing trees. The linked list is an example of an accumulation variable or /state/. Each iteration of the algorithm takes the current element and state, applies some binary function to the two and creates a new state. In the STL, this algorithm is called `std::accumulate()`. In many other languages, it is called /fold/. Let's see how to implement a fold algorithm with Proto transforms. 893 894All Proto grammars can optionally accept a state parameter in addition to the expression to transform. If you want to fold a tree to a list, you'll need to make use of the state parameter to pass around the list you've built so far. As for the list, the Boost.Fusion library provides a `fusion::cons<>` type from which you can build heterogeneous lists. The type `fusion::nil` represents an empty list. 895 896Below is a grammar that recognizes output expressions like `cout_ << 42 << '\n'` and puts the arguments into a Fusion list. It is explained below. 897 898 // Fold the terminals in output statements like 899 // "cout_ << 42 << '\n'" into a Fusion cons-list. 900 struct FoldToList 901 : proto::or_< 902 // Don't add the ostream terminal to the list 903 proto::when< 904 proto::terminal< std::ostream & > 905 , proto::_state 906 > 907 // Put all other terminals at the head of the 908 // list that we're building in the "state" parameter 909 , proto::when< 910 proto::terminal<_> 911 , fusion::cons<proto::_value, proto::_state>( 912 proto::_value, proto::_state 913 ) 914 > 915 // For left-shift operations, first fold the right 916 // child to a list using the current state. Use 917 // the result as the state parameter when folding 918 // the left child to a list. 919 , proto::when< 920 proto::shift_left<FoldToList, FoldToList> 921 , FoldToList( 922 proto::_left 923 , FoldToList(proto::_right, proto::_state) 924 ) 925 > 926 > 927 {}; 928 929Before reading on, see if you can apply what you know already about object, callable and primitive transforms to figure out how this grammar works. 930 931When you use the `FoldToList` function, you'll need to pass two arguments: the expression to fold, and the initial state: an empty list. Those two arguments get passed around to each transform. We learned previously that `proto::_value` is a primitive transform that accepts a terminal expression and extracts its value. What we didn't know until now was that it also accepts the current state /and ignores it/. `proto::_state` is also a primitive transform. It accepts the current expression, which it ignores, and the current state, which it returns. 932 933When we find a terminal, we stick it at the head of the cons list, using the current state as the tail of the list. (The first alternate causes the `ostream` to be skipped. We don't want `cout` in the list.) When we find a shift-left node, we apply the following transform: 934 935 // Fold the right child and use the result as 936 // state while folding the right. 937 FoldToList( 938 proto::_left 939 , FoldToList(proto::_right, proto::_state) 940 ) 941 942You can read this transform as follows: using the current state, fold the right child to a list. Use the new list as the state while folding the left child to a list. 943 944[tip If your compiler is Microsoft Visual C++, you'll find that the above transform does not compile. The compiler has bugs with its handling of nested function types. You can work around the bug by wrapping the inner transform in `proto::call<>` as follows: 945 946`` 947 FoldToList( 948 proto::_left 949 , proto::call<FoldToList(proto::_right, proto::_state)> 950 ) 951`` 952 953`proto::call<>` turns a callable transform into a primitive transform, but more on that later. 954] 955 956Now that we have defined the `FoldToList` function object, we can use it to turn output expressions into lists as follows: 957 958 proto::terminal<std::ostream &>::type const cout_ = {std::cout}; 959 960 // This is the type of the list we build below 961 typedef 962 fusion::cons< 963 int 964 , fusion::cons< 965 double 966 , fusion::cons< 967 char 968 , fusion::nil 969 > 970 > 971 > 972 result_type; 973 974 // Fold an output expression into a Fusion list, using 975 // fusion::nil as the initial state of the transformation. 976 FoldToList to_list; 977 result_type args = to_list(cout_ << 1 << 3.14 << '\n', fusion::nil()); 978 979 // Now "args" is the list: {1, 3.14, '\n'} 980 981When writing transforms, "fold" is such a basic operation that Proto provides a number of built-in fold transforms. We'll get to them later. For now, rest assured that you won't always have to stretch your brain so far to do such basic things. 982 983[endsect] 984 985[/================================================] 986[section:data Passing Auxiliary Data to Transforms] 987[/================================================] 988 989In the last section, we saw that we can pass a second parameter to grammars with transforms: an accumulation variable or /state/ that gets updated as your transform executes. There are times when your transforms will need to access auxiliary data that does /not/ accumulate, so bundling it with the state parameter is impractical. Instead, you can pass auxiliary data as a third parameter, known as the /data/ parameter. 990 991Let's modify our previous example so that it writes each terminal to `std::cout` before it puts it into a list. This could be handy for debugging your transforms, for instance. We can make it general by passing a `std::ostream` into the transform in the data parameter. Within the transform itself, we can retrieve the `ostream` with the _data_pt_ transform. The strategy is as follows: use the _and_ transform to chain two actions. The second action will create the `fusion::cons<>` node as before. The first action, however, will display the current expression. For that, we first construct an instance of [classref boost::proto::functional::display_expr `proto::functional::display_expr`] and then call it. 992 993 // Fold the terminals in output statements like 994 // "cout_ << 42 << '\n'" into a Fusion cons-list. 995 struct FoldToList 996 : proto::or_< 997 // Don't add the ostream terminal to the list 998 proto::when< 999 proto::terminal< std::ostream & > 1000 , proto::_state 1001 > 1002 // Put all other terminals at the head of the 1003 // list that we're building in the "state" parameter 1004 , proto::when< 1005 proto::terminal<_> 1006 , proto::and_< 1007 // First, write the terminal to an ostream passed 1008 // in the data parameter 1009 proto::lazy< 1010 proto::make<proto::functional::display_expr(proto::_data)>(_) 1011 > 1012 // Then, constuct the new cons list. 1013 , fusion::cons<proto::_value, proto::_state>( 1014 proto::_value, proto::_state 1015 ) 1016 > 1017 > 1018 // For left-shift operations, first fold the right 1019 // child to a list using the current state. Use 1020 // the result as the state parameter when folding 1021 // the left child to a list. 1022 , proto::when< 1023 proto::shift_left<FoldToList, FoldToList> 1024 , FoldToList( 1025 proto::_left 1026 , FoldToList(proto::_right, proto::_state, proto::_data) 1027 , proto::_data 1028 ) 1029 > 1030 > 1031 {}; 1032 1033This is a lot to take in, no doubt. But focus on the second `when` clause above. It says: when you find a terminal, first display the terminal using the `ostream` you find in the data parameter, then take the value of the terminal and the current state to build a new `cons` list. The function object `display_expr` does the job of printing the terminal, and `proto::and_<>` chains the actions together and executes them in sequence, returning the result of the last one. 1034 1035[def __the_expr__ ['the-expr]] 1036 1037[note Also new is _lazy_pt_. Sometimes you don't have a ready-made callable object to execute. Instead, you want to first make one and /then/ execute it. Above, we need to create a `display_expr`, initializing it with our `ostream`. After that, we want to invoke it by passing it the current expression. It's as if we were doing `display_expr(std::cout)(__the_expr__)`. We achieve this two-phase evaluation using `proto::lazy<>`. If this doesn't make sense yet, don't worry about it.] 1038 1039We can use the above transform as before, but now we can pass an `ostream` as the third parameter and get to watch the transform in action. Here's a sample usage: 1040 1041 proto::terminal<std::ostream &>::type const cout_ = {std::cout}; 1042 1043 // This is the type of the list we build below 1044 typedef 1045 fusion::cons< 1046 int 1047 , fusion::cons< 1048 double 1049 , fusion::cons< 1050 char 1051 , fusion::nil 1052 > 1053 > 1054 > 1055 result_type; 1056 1057 // Fold an output expression into a Fusion list, using 1058 // fusion::nil as the initial state of the transformation. 1059 // Pass std::cout as the data parameter so that we can track 1060 // the progress of the transform on the console. 1061 FoldToList to_list; 1062 result_type args = to_list(cout_ << 1 << 3.14 << '\n', fusion::nil(), std::cout); 1063 1064 // Now "args" is the list: {1, 3.14, '\n'} 1065 1066This code displays the following: 1067 1068[pre terminal( 1069) 1070terminal(3.14) 1071terminal(1)] 1072 1073This is a rather round-about way of demonstrating that you can pass extra data to a transform as a third parameter. There are no restrictions on what this parameter can be, and, unlike the state parameter, Proto will never mess with it. 1074 1075[heading Transform Environment Variables] 1076 1077[note ['This is an advanced topic. Feel free to skip if you are new to Proto.]] 1078 1079The example above uses the data parameter as a transport mechanism for an unstructured blob of data; in this case, a reference to an `ostream`. As your Proto algorithms become more sophisticated, you may find that an unstructured blob of data isn't terribly convenient to work with. Different parts of your algorithm may be interested in different bits of data. What you want, instead, is a way to pass in a collection of /environment variables/ to a transform, like a collection of key\/value pairs. Then, you can easily get at the piece of data you want by asking the data parameter for the value associated with a particular key. Proto's /transform environments/ give you just that. 1080 1081Let's start by defining a key. 1082 1083 BOOST_PROTO_DEFINE_ENV_VAR(mykey_type, mykey); 1084 1085This defines a global constant `mykey` with the type `mykey_type`. We can use `mykey` to store a piece of assiciated data in a transform environment, as so: 1086 1087 // Call the MyEval algorithm with a transform environment containing 1088 // two key/value pairs: one for proto::data and one for mykey 1089 MyEval()( expr, state, (proto::data = 42, mykey = "hello world") ); 1090 1091The above means to invoke the `MyEval` algorithm with three parameters: an expression, an initial state, and a transform environment containing two key\/value pairs. 1092 1093From within a Proto algorithm, you can access the values associated with different keys using the [classref boost::proto::_env_var `proto::_env_var<>`] transform. For instance, `proto::_env_var<mykey_type>` would fetch the value `"hello world"` from the transform environment created above. 1094 1095The `proto::_data` transform has some additional smarts. Rather than always returning the third parameter regarless of whether it is a blob or a transform environment, it checks first to see if it's a blob or not. If so, that's what gets returned. If not, it returns the value associated with the `proto::data` key. In the above example, that would be the value `42`. 1096 1097There's a small host of functions, metafunction, and classes that you can use to create and manipulate transform environments, some for testing whether an object is a transform environment, some for coercing an object to be a transform environment, and some for querying a transform environment whether or not is has a value for a particular key. For an exhaustive treatment of the topic, check out the reference for the [headerref boost/proto/transform/env.hpp] header. 1098 1099[endsect] 1100 1101[section:implicit_params Implicit Parameters to Primitive Transforms] 1102 1103Let's use `FoldToList` example from the previous two sections to illustrate some other niceties of Proto transforms. We've seen that grammars, when used as function objects, can accept up to 3 parameters, and that when using these grammars in callable transforms, you can also specify up to 3 parameters. Let's take another look at the transform associated with non-terminals from the last section: 1104 1105 FoldToList( 1106 proto::_left 1107 , FoldToList(proto::_right, proto::_state, proto::_data) 1108 , proto::_data 1109 ) 1110 1111Here we specify all three parameters to both invocations of the `FoldToList` grammar. But we don't have to specify all three. If we don't specify a third parameter, `proto::_data` is assumed. Likewise for the second parameter and `proto::_state`. So the above transform could have been written more simply as: 1112 1113 FoldToList( 1114 proto::_left 1115 , StringCopy(proto::_right) 1116 ) 1117 1118The same is true for any primitive transform. The following are all equivalent: 1119 1120[table Implicit Parameters to Primitive Transforms 1121 [[Equivalent Transforms]] 1122 [[`proto::when<_, FoldToList>`]] 1123 [[`proto::when<_, FoldToList()>`]] 1124 [[`proto::when<_, FoldToList(_)>`]] 1125 [[`proto::when<_, FoldToList(_, proto::_state)>`]] 1126 [[`proto::when<_, FoldToList(_, proto::_state, proto::_data)>`]] 1127] 1128 1129[note *Grammars Are Primitive Transforms Are Function Objects* 1130 1131So far, we've said that all Proto grammars are function objects. But it's more accurate to say that Proto grammars are primitive transforms -- a special kind of function object that takes between 1 and 3 arguments, and that Proto knows to treat specially when used in a callable transform, as in the table above.] 1132 1133[note *Not All Function Objects Are Primitive Transforms* 1134 1135You might be tempted now to drop the `_state` and `_data` parameters for all your callable transforms. That would be an error. You can only do that for primitive transforms, and not all callables are primitive transforms. Later on, we'll see what distinguishes ordinary callables from their more powerful primitive transfor cousins, but the short version is this: primitive transforms inherit from [classref boost::proto::transform `proto::transform<>`].] 1136 1137Once you know that primitive transforms will always receive all three parameters -- expression, state, and data -- it makes things possible that wouldn't be otherwise. For instance, consider that for binary expressions, these two transforms are equivalent. Can you see why? 1138 1139[table Two Equivalent Transforms 1140 [[Without [^proto::reverse_fold<>]][With [^proto::reverse_fold<>]]] 1141 [[``FoldToList( 1142 proto::_left 1143 , FoldToList(proto::_right, proto::_state, proto::_data) 1144 , proto::_data 1145)`` 1146][``proto::reverse_fold<_, proto::_state, FoldToList>``]] 1147] 1148 1149[endsect] 1150 1151[/==================================================] 1152[section:unpacking_expressions Unpacking Expressions] 1153[/==================================================] 1154 1155Processing expressions with an arbitrary number of children can be a pain. What if you want to do something to each child, then pass the results as arguments to some other function? Can you do it just once without worrying about how many children an expression has? Yes. This is where Proto's /unpacking expressions/ come in handy. Unpacking expressions give you a way to write callable and object transforms that handle ['n]-ary expressions. 1156 1157[note *Inspired by C++11 Variadic Templates* 1158 1159Proto's unpacking expressions take inspiration from the C++11 feature of the same name. If you are familiar with variadic functions, and in particular how to expand a function parameter pack, this discussion should seem very familiar. However, this feature doesn't actually use any C++11 features, so the code describe here will work with any compliant C++98 compiler.] 1160 1161[heading Example: A C++ Expression Evaluator] 1162 1163Proto has the built-in _default_pt_ transform for evaluating Proto expressions in a C++-ish way. But if it didn't, it wouldn't be too hard to implement one from scratch using Proto's unpacking patterns. The transform `eval` below does just that. 1164 1165 // A callable polymorphic function object that takes an unpacked expression 1166 // and a tag, and evaluates the expression. A plus tag and two operands adds 1167 // them with operator +, for instance. 1168 struct do_eval : proto::callable 1169 { 1170 typedef double result_type; 1171 1172 #define UNARY_OP(TAG, OP) \ 1173 template<typename Arg> \ 1174 double operator()(proto::tag::TAG, Arg arg) const \ 1175 { \ 1176 return OP arg; \ 1177 } \ 1178 /**/ 1179 1180 #define BINARY_OP(TAG, OP) \ 1181 template<typename Left, typename Right> \ 1182 double operator()(proto::tag::TAG, Left left, Right right) const \ 1183 { \ 1184 return left OP right; \ 1185 } \ 1186 /**/ 1187 1188 UNARY_OP(negate, -) 1189 BINARY_OP(plus, +) 1190 BINARY_OP(minus, -) 1191 BINARY_OP(multiplies, *) 1192 BINARY_OP(divides, /) 1193 /*... others ...*/ 1194 }; 1195 1196 struct eval 1197 : proto::or_< 1198 // Evaluate terminals by simply returning their value 1199 proto::when<proto::terminal<_>, proto::_value> 1200 1201 // Non-terminals are handled by unpacking the expression, 1202 // recursively calling eval on each child, and passing 1203 // the results along with the expression's tag to do_eval 1204 // defined above. 1205 , proto::otherwise<do_eval(proto::tag_of<_>(), eval(proto::pack(_))...)> 1206 // UNPACKING PATTERN HERE -------------------^^^^^^^^^^^^^^^^^^^^^^^^ 1207 > 1208 {}; 1209 1210The bulk of the above code is devoted to the `do_eval` function object that maps tag types to behaviors, but the interesting bit is the definition of the `eval` algorithm at the bottom. Terminals are handled quite simply, but non-terminals could be unary, binary, ternary, even ['n]-ary if we consider function call expressions. The `eval` algorithm handles this uniformly with the help of an unpacking pattern. 1211 1212Non-terminals are evaluated with this callable transform: 1213 1214 do_eval(proto::tag_of<_>(), eval(proto::pack(_))...) 1215 1216You can read this as: call the `do_eval` function object with the tag of the current expression and all its children after they have each been evaluated with `eval`. The unpacking pattern is the bit just before the ellipsis: `eval(proto::pack(_))`. 1217 1218What's going on here is this. The unpacking expression gets repeated once for each child in the expression currently being evaluated. In each repetition, the type `proto::pack(_)` gets replaced with [^proto::_child_c<['N]>]. So, if a unary expression is passed to `eval`, it actually gets evaluated like this: 1219 1220 // After the unpacking pattern is expanded for a unary expression 1221 do_eval(proto::tag_of<_>(), eval(proto::_child_c<0>)) 1222 1223And when passed a binary expression, the unpacking pattern expands like this: 1224 1225 // After the unpacking pattern is expanded for a binary expression 1226 do_eval(proto::tag_of<_>(), eval(proto::_child_c<0>), eval(proto::_child_c<1>)) 1227 1228Although it can't happen in our example, when passed a terminal, the unpacking pattern expands such that it extracts the value from the terminal instead of the children. So it gets handled like this: 1229 1230 // If a terminal were passed to this transform, Proto would try 1231 // to evaluate it like this, which would fail: 1232 do_eval(proto::tag_of<_>(), eval(proto::_value)) 1233 1234That doesn't make sense. `proto::_value` would return something that isn't a Proto expression, and `eval` wouldn't be able to evaluate it. Proto algorithms don't work unless you pass them Proto expressions. 1235 1236[note *Kickin' It Old School* 1237 1238You may be thinking, my compiler doesn't support C++11 variadic templates! How can this possibly work? The answer is simple: The `...` above isn't a C++11 pack expansion. It's actually an old-school C-style vararg. Remember that callable and object transforms are /function types/. A transform with one of these pseudo-pack expansions is really just the type of a boring, old vararg function. Proto just interprets it differently.] 1239 1240Unpacking patterns are very expressive. Any callable or object transform can be used as an unpacking pattern, so long as `proto::pack(_)` appears exactly once somewhere within it. This gives you a lot of flexibility in how you want to process the children of an expression before passing them on to some function object or object constructor. 1241 1242[endsect] 1243 1244[/=============================================================] 1245[section:external_transforms Separating Grammars And Transforms] 1246[/=============================================================] 1247 1248[note This is an advanced topic that is only necessary for people defining large EDSLs. Feel free to skip this if you're just getting started with Proto.] 1249 1250So far, we've seen examples of grammars with embedded transforms. In practice, grammars can get pretty large, and you may want to use them to drive several different computations. For instance, you may have a grammar for a linear algebra domain, and you may want to use it to compute the shape of the result (vector or matrix?) and also to compute the result optimally. You don't want to have to copy and paste the whole shebang just to tweak one of the embedded transforms. What you want instead is to define the grammar once, and specify the transforms later when you're ready to evaluate an expression. For that, you use /external transforms/. The pattern you'll use is this: replace one or more of the transforms in your grammar with the special placeholder _external_transform_. Then, you'll create a bundle of transforms that you will pass to the grammar in the data parameter (the 3rd parameter after the expression and state) when evaluating it. 1251 1252To illustrate external transforms, we'll build a calculator evaluator that can be configured to throw an exception on division by zero. Here is a bare-bones front end that defines a domain, a grammar, an expression wrapper, and some placeholder terminals. 1253 1254 #include <boost/assert.hpp> 1255 #include <boost/mpl/int.hpp> 1256 #include <boost/fusion/container/vector.hpp> 1257 #include <boost/fusion/container/generation/make_vector.hpp> 1258 #include <boost/proto/proto.hpp> 1259 namespace mpl = boost::mpl; 1260 namespace proto = boost::proto; 1261 namespace fusion = boost::fusion; 1262 1263 // The argument placeholder type 1264 template<typename I> struct placeholder : I {}; 1265 1266 // The grammar for valid calculator expressions 1267 struct calc_grammar 1268 : proto::or_< 1269 proto::terminal<placeholder<proto::_> > 1270 , proto::terminal<int> 1271 , proto::plus<calc_grammar, calc_grammar> 1272 , proto::minus<calc_grammar, calc_grammar> 1273 , proto::multiplies<calc_grammar, calc_grammar> 1274 , proto::divides<calc_grammar, calc_grammar> 1275 > 1276 {}; 1277 1278 template<typename E> struct calc_expr; 1279 struct calc_domain : proto::domain<proto::generator<calc_expr> > {}; 1280 1281 template<typename E> 1282 struct calc_expr 1283 : proto::extends<E, calc_expr<E>, calc_domain> 1284 { 1285 calc_expr(E const &e = E()) : calc_expr::proto_extends(e) {} 1286 }; 1287 1288 calc_expr<proto::terminal<placeholder<mpl::int_<0> > >::type> _1; 1289 calc_expr<proto::terminal<placeholder<mpl::int_<1> > >::type> _2; 1290 1291 int main() 1292 { 1293 // Build a calculator expression, and do nothing with it. 1294 (_1 + _2); 1295 } 1296 1297Now, let's embed transforms into `calc_grammar` so that we can use it to evaluate calculator expressions: 1298 1299 // The calculator grammar with embedded transforms for evaluating expression. 1300 struct calc_grammar 1301 : proto::or_< 1302 proto::when< 1303 proto::terminal<placeholder<proto::_> > 1304 , proto::functional::at(proto::_state, proto::_value) 1305 > 1306 , proto::when< 1307 proto::terminal<int> 1308 , proto::_value 1309 > 1310 , proto::when< 1311 proto::plus<calc_grammar, calc_grammar> 1312 , proto::_default<calc_grammar> 1313 > 1314 , proto::when< 1315 proto::minus<calc_grammar, calc_grammar> 1316 , proto::_default<calc_grammar> 1317 > 1318 , proto::when< 1319 proto::multiplies<calc_grammar, calc_grammar> 1320 , proto::_default<calc_grammar> 1321 > 1322 , proto::when< 1323 proto::divides<calc_grammar, calc_grammar> 1324 , proto::_default<calc_grammar> 1325 > 1326 > 1327 {}; 1328 1329With this definition of `calc_grammar` we can evaluate expressions by passing along a Fusion vector containing the values to use for the `_1` and `_2` placeholders: 1330 1331 int result = calc_grammar()(_1 + _2, fusion::make_vector(3, 4)); 1332 BOOST_ASSERT(result == 7); 1333 1334We also want an alternative evaluation strategy that checks for division by zero and throws an exception. Just how ridiculous would it be to copy the entire `calc_grammar` just to change the one line that transforms division expressions?! External transforms are ideally suited to this problem. 1335 1336First, we give the division rule in our grammar a "name"; that is, we make it a struct. We'll use this unique type later to dispatch to the right transforms. 1337 1338 struct calc_grammar; 1339 struct divides_rule : proto::divides<calc_grammar, calc_grammar> {}; 1340 1341Next, we change `calc_grammar` to make the handling of division expressions external. 1342 1343 // The calculator grammar with an external transform for evaluating 1344 // division expressions. 1345 struct calc_grammar 1346 : proto::or_< 1347 /* ... as before ... */ 1348 , proto::when< 1349 divides_rule 1350 , proto::external_transform 1351 > 1352 > 1353 {}; 1354 1355The use of _external_transform_ above makes the handling of division expressions externally parameterizeable. 1356 1357Next, we use _external_transforms_ (note the trailing 's') to capture our evaluation strategy in a bundle that we can pass along to the transform in the data parameter. Read on for the explanation. 1358 1359 // Evaluate division nodes as before 1360 struct non_checked_division 1361 : proto::external_transforms< 1362 proto::when< divides_rule, proto::_default<calc_grammar> > 1363 > 1364 {}; 1365 1366 /* ... */ 1367 1368 non_checked_division non_checked; 1369 int result2 = calc_grammar()(_1 / _2, fusion::make_vector(6, 2), non_checked); 1370 1371The struct `non_cecked_division` associates the transform `proto::_default<calc_grammar>` with the `divides_rule` grammar rule. An instance of that struct is passed along as the third parameter when invoking `calc_grammar`. 1372 1373Now, let's implement checked division. The rest should be unsurprising. 1374 1375 struct division_by_zero : std::exception {}; 1376 1377 struct do_checked_divide : proto::callable 1378 { 1379 typedef int result_type; 1380 int operator()(int left, int right) const 1381 { 1382 if (right == 0) throw division_by_zero(); 1383 return left / right; 1384 } 1385 }; 1386 1387 struct checked_division 1388 : proto::external_transforms< 1389 proto::when< 1390 divides_rule 1391 , do_checked_divide(calc_grammar(proto::_left), calc_grammar(proto::_right)) 1392 > 1393 > 1394 {}; 1395 1396 /* ... */ 1397 1398 try 1399 { 1400 checked_division checked; 1401 int result3 = calc_grammar_extern()(_1 / _2, fusion::make_vector(6, 0), checked); 1402 } 1403 catch(division_by_zero) 1404 { 1405 std::cout << "caught division by zero!\n"; 1406 } 1407 1408The above code demonstrates how a single grammar can be used with different transforms specified externally. This makes it possible to reuse a grammar to drive several different computations. 1409 1410[heading Separating Data From External Transforms] 1411 1412As described above, the external transforms feature usurps the data parameter, which is intended to be a place where you can pass arbitrary data, and gives it a specific meaning. But what if you are already using the data parameter for something else? The answer is to use a transform environment. By associating your external transforms with the `proto::transforms` key, you are free to pass arbitrary data in other slots. 1413 1414To continue the above example, what if we also needed to pass a piece of data into our transform along with the external transforms? It would look like this: 1415 1416 int result3 = calc_grammar_extern()( 1417 _1 / _2 1418 , fusion::make_vector(6, 0) 1419 , (proto::data = 42, proto::transforms = checked) 1420 ); 1421 1422In the above invocation of the `calc_grammar_extern` algorithm, the map of external transforms is associated with the `proto::transforms` key and passed to the algorithm in a transform environment. Also in the transform environment is a key\/value pair that associates the value `42` with the `proto::data` key. 1423 1424[endsect] 1425 1426[/====================================================] 1427[section:canned_transforms Proto's Built-In Transforms] 1428[/====================================================] 1429 1430[def _N_ [~N]] 1431[def _G_ [~G]] 1432[def _G0_ [~G0]] 1433[def _G1_ [~G1]] 1434[def _CT_ [~CT]] 1435[def _OT_ [~OT]] 1436[def _ET_ [~ET]] 1437[def _ST_ [~ST]] 1438[def _FT_ [~FT]] 1439 1440Primitive transforms are the building blocks for more interesting composite transforms. Proto defines a bunch of generally useful primitive transforms. They are summarized below. 1441 1442[variablelist 1443 [[_value_pt_] 1444 [Given a terminal expression, return the value of the terminal.]] 1445 [[_child_c_pt_] 1446 [Given a non-terminal expression, `proto::_child_c<_N_>` returns the _N_-th 1447 child.]] 1448 [[_child_pt_] 1449 [A synonym for `proto::_child_c<0>`.]] 1450 [[_left_pt_] 1451 [A synonym for `proto::_child_c<0>`.]] 1452 [[_right_pt_] 1453 [A synonym for `proto::_child_c<1>`.]] 1454 [[_expr_pt_] 1455 [Returns the current expression unmodified.]] 1456 [[_state_pt_] 1457 [Returns the current state unmodified.]] 1458 [[_data_pt_] 1459 [Returns the current data unmodified.]] 1460 [[_call_pt_] 1461 [For a given callable transform `_CT_`, `proto::call<_CT_>` turns the 1462 callable transform into a primitive transform. This is useful for 1463 disambiguating callable transforms from object transforms, and also for 1464 working around compiler bugs with nested function types.]] 1465 [[_make_pt_] 1466 [For a given object transform `_OT_`, `proto::make<_OT_>` turns the 1467 object transform into a primitive transform. This is useful for 1468 disambiguating object transforms from callable transforms, and also for 1469 working around compiler bugs with nested function types.]] 1470 [[_default_pt_] 1471 [Given a grammar _G_, `proto::_default<_G_>` evaluates the current node 1472 according to the standard C++ meaning of the operation the node represents. 1473 For instance, if the current node is a binary plus node, the two children 1474 will both be evaluated according to `_G_` and the results will be added and 1475 returned. The return type is deduced with the help of the Boost.Typeof 1476 library.]] 1477 [[_fold_pt_] 1478 [Given three transforms `_ET_`, `_ST_`, and `_FT_`, 1479 `proto::fold<_ET_, _ST_, _FT_>` first evaluates `_ET_` to obtain a Fusion 1480 sequence and `_ST_` to obtain an initial state for the fold, and then 1481 evaluates `_FT_` for each element in the sequence to generate the next 1482 state from the previous.]] 1483 [[_reverse_fold_pt_] 1484 [Like _fold_pt_, except the elements in the Fusion sequence are iterated in 1485 reverse order.]] 1486 [[_fold_tree_pt_] 1487 [Like `proto::fold<_ET_, _ST_, _FT_>`, except that the result of the `_ET_` 1488 transform is treated as an expression tree that is /flattened/ to generate 1489 the sequence to be folded. Flattening an expression tree causes child nodes 1490 with the same tag type as the parent to be put into sequence. For instance, 1491 `a >> b >> c` would be flattened to the sequence \[`a`, `b`, `c`\], and this 1492 is the sequence that would be folded.]] 1493 [[_reverse_fold_tree_pt_] 1494 [Like _fold_tree_pt_, except that the flattened sequence is iterated in 1495 reverse order.]] 1496 [[_lazy_pt_] 1497 [A combination of _make_pt_ and _call_pt_ that is useful when the nature of 1498 the transform depends on the expression, state and/or data parameters. 1499 `proto::lazy<R(A0,A1...An)>` first evaluates `proto::make<R()>` to compute a 1500 callable type `R2`. Then, it evaluates `proto::call<R2(A0,A1...An)>`.]] 1501] 1502 1503[/============================================] 1504[heading All Grammars Are Primitive Transforms] 1505[/============================================] 1506 1507In addition to the above primitive transforms, all of Proto's grammar elements are also primitive transforms. Their behaviors are described below. 1508 1509[variablelist 1510 [[_wild_] 1511 [Return the current expression unmodified.]] 1512 [[_or_] 1513 [For the specified set of alternate sub-grammars, find the one that matches 1514 the given expression and apply its associated transform.]] 1515 [[_and_] 1516 [For the given set of sub-grammars, apply all the associated transforms and 1517 return the result of the last.]] 1518 [[_not_] 1519 [Return the current expression unmodified.]] 1520 [[_if_] 1521 [Given three transforms, evaluate the first and treat the result as a 1522 compile-time Boolean value. If it is true, evaluate the second transform. 1523 Otherwise, evaluate the third.]] 1524 [[_switch_] 1525 [As with _or_, find the sub-grammar that matches the given expression and 1526 apply its associated transform.]] 1527 [[_terminal_] 1528 [Return the current terminal expression unmodified.]] 1529 [[_plus_, _nary_expr_, et. al.] 1530 [A Proto grammar that matches a non-terminal such as 1531 `proto::plus<_G0_, _G1_>`, when used as a primitive transform, creates a new 1532 plus node where the left child is transformed according to `_G0_` and the 1533 right child with `_G1_`.]] 1534] 1535 1536[/=================================] 1537[heading The Pass-Through Transform] 1538[/=================================] 1539 1540Note the primitive transform associated with grammar elements such as _plus_ described above. They possess a so-called /pass-through/ transform. The pass-through transform accepts an expression of a certain tag type (say, `proto::tag::plus`) and creates a new expression of the same tag type, where each child expression is transformed according to the corresponding child grammar of the pass-through transform. So for instance this grammar ... 1541 1542 proto::function< X, proto::vararg<Y> > 1543 1544... matches function expressions where the first child matches the `X` grammar and the rest match the `Y` grammar. When used as a transform, the above grammar will create a new function expression where the first child is transformed according to `X` and the rest are transformed according to `Y`. 1545 1546The following class templates in Proto can be used as grammars with pass-through transforms: 1547 1548[table Class Templates With Pass-Through Transforms 1549 [[Templates with Pass-Through Transforms]] 1550 [[`proto::unary_plus<>`]] 1551 [[`proto::negate<>`]] 1552 [[`proto::dereference<>`]] 1553 [[`proto::complement<>`]] 1554 [[`proto::address_of<>`]] 1555 [[`proto::logical_not<>`]] 1556 [[`proto::pre_inc<>`]] 1557 [[`proto::pre_dec<>`]] 1558 [[`proto::post_inc<>`]] 1559 [[`proto::post_dec<>`]] 1560 [[`proto::shift_left<>`]] 1561 [[`proto::shift_right<>`]] 1562 [[`proto::multiplies<>`]] 1563 [[`proto::divides<>`]] 1564 [[`proto::modulus<>`]] 1565 [[`proto::plus<>`]] 1566 [[`proto::minus<>`]] 1567 [[`proto::less<>`]] 1568 [[`proto::greater<>`]] 1569 [[`proto::less_equal<>`]] 1570 [[`proto::greater_equal<>`]] 1571 [[`proto::equal_to<>`]] 1572 [[`proto::not_equal_to<>`]] 1573 [[`proto::logical_or<>`]] 1574 [[`proto::logical_and<>`]] 1575 [[`proto::bitwise_and<>`]] 1576 [[`proto::bitwise_or<>`]] 1577 [[`proto::bitwise_xor<>`]] 1578 [[`proto::comma<>`]] 1579 [[`proto::mem_ptr<>`]] 1580 [[`proto::assign<>`]] 1581 [[`proto::shift_left_assign<>`]] 1582 [[`proto::shift_right_assign<>`]] 1583 [[`proto::multiplies_assign<>`]] 1584 [[`proto::divides_assign<>`]] 1585 [[`proto::modulus_assign<>`]] 1586 [[`proto::plus_assign<>`]] 1587 [[`proto::minus_assign<>`]] 1588 [[`proto::bitwise_and_assign<>`]] 1589 [[`proto::bitwise_or_assign<>`]] 1590 [[`proto::bitwise_xor_assign<>`]] 1591 [[`proto::subscript<>`]] 1592 [[`proto::if_else_<>`]] 1593 [[`proto::function<>`]] 1594 [[`proto::unary_expr<>`]] 1595 [[`proto::binary_expr<>`]] 1596 [[`proto::nary_expr<>`]] 1597] 1598 1599[/=====================================================] 1600[heading The Many Roles of Proto Operator Metafunctions] 1601[/=====================================================] 1602 1603We've seen templates such as _terminal_, _plus_ and _nary_expr_ fill many roles. They are metafunction that generate expression types. They are grammars that match expression types. And they are primitive transforms. The following code samples show examples of each. 1604 1605[*As Metafunctions ...] 1606 1607 // proto::terminal<> and proto::plus<> are metafunctions 1608 // that generate expression types: 1609 typedef proto::terminal<int>::type int_; 1610 typedef proto::plus<int_, int_>::type plus_; 1611 1612 int_ i = {42}, j = {24}; 1613 plus_ p = {i, j}; 1614 1615[*As Grammars ...] 1616 1617 // proto::terminal<> and proto::plus<> are grammars that 1618 // match expression types 1619 struct Int : proto::terminal<int> {}; 1620 struct Plus : proto::plus<Int, Int> {}; 1621 1622 BOOST_MPL_ASSERT(( proto::matches< int_, Int > )); 1623 BOOST_MPL_ASSERT(( proto::matches< plus_, Plus > )); 1624 1625[*As Primitive Transforms ...] 1626 1627 // A transform that removes all unary_plus nodes in an expression 1628 struct RemoveUnaryPlus 1629 : proto::or_< 1630 proto::when< 1631 proto::unary_plus<RemoveUnaryPlus> 1632 , RemoveUnaryPlus(proto::_child) 1633 > 1634 // Use proto::terminal<> and proto::nary_expr<> 1635 // both as grammars and as primitive transforms. 1636 , proto::terminal<_> 1637 , proto::nary_expr<_, proto::vararg<RemoveUnaryPlus> > 1638 > 1639 {}; 1640 1641 int main() 1642 { 1643 proto::literal<int> i(0); 1644 1645 proto::display_expr( 1646 +i - +(i - +i) 1647 ); 1648 1649 proto::display_expr( 1650 RemoveUnaryPlus()( +i - +(i - +i) ) 1651 ); 1652 } 1653 1654The above code displays the following, which shows that unary plus nodes have been stripped from the expression: 1655 1656[pre 1657minus( 1658 unary_plus( 1659 terminal(0) 1660 ) 1661 , unary_plus( 1662 minus( 1663 terminal(0) 1664 , unary_plus( 1665 terminal(0) 1666 ) 1667 ) 1668 ) 1669) 1670minus( 1671 terminal(0) 1672 , minus( 1673 terminal(0) 1674 , terminal(0) 1675 ) 1676) 1677] 1678 1679[endsect] 1680 1681[/======================================================] 1682[section:primitives Building Custom Primitive Transforms] 1683[/======================================================] 1684 1685In previous sections, we've seen how to compose larger transforms out of smaller transforms using function types. The smaller transforms from which larger transforms are composed are /primitive transforms/, and Proto provides a bunch of common ones such as `_child0` and `_value`. In this section we'll see how to author your own primitive transforms. 1686 1687[note There are a few reasons why you might want to write your own primitive transforms. For instance, your transform may be complicated, and composing it out of primitives becomes unwieldy. You might also need to work around compiler bugs on legacy compilers that make composing transforms using function types problematic. Finally, you might also decide to define your own primitive transforms to improve compile times. Since Proto can simply invoke a primitive transform directly without having to process arguments or differentiate callable transforms from object transforms, primitive transforms are more efficient.] 1688 1689Primitive transforms inherit from `proto::transform<>` and have a nested `impl<>` template that inherits from `proto::transform_impl<>`. For example, this is how Proto defines the `_child_c<_N_>` transform, which returns the _N_-th child of the current expression: 1690 1691 namespace boost { namespace proto 1692 { 1693 // A primitive transform that returns N-th child 1694 // of the current expression. 1695 template<int N> 1696 struct _child_c : transform<_child_c<N> > 1697 { 1698 template<typename Expr, typename State, typename Data> 1699 struct impl : transform_impl<Expr, State, Data> 1700 { 1701 typedef 1702 typename result_of::child_c<Expr, N>::type 1703 result_type; 1704 1705 result_type operator ()( 1706 typename impl::expr_param expr 1707 , typename impl::state_param state 1708 , typename impl::data_param data 1709 ) const 1710 { 1711 return proto::child_c<N>(expr); 1712 } 1713 }; 1714 }; 1715 1716 // Note that _child_c<N> is callable, so that 1717 // it can be used in callable transforms, as: 1718 // _child_c<0>(_child_c<1>) 1719 template<int N> 1720 struct is_callable<_child_c<N> > 1721 : mpl::true_ 1722 {}; 1723 }} 1724 1725The `proto::transform<>` base class provides the `operator()` overloads and the nested `result<>` template that make your transform a valid function object. These are implemented in terms of the nested `impl<>` template you define. 1726 1727The `proto::transform_impl<>` base class is a convenience. It provides some nested typedefs that are generally useful. They are specified in the table below: 1728 1729[table proto::transform_impl<Expr, State, Data> typedefs 1730[[typedef][Equivalent To]] 1731[[`expr`][`typename remove_reference<Expr>::type`]] 1732[[`state`][`typename remove_reference<State>::type`]] 1733[[`data`][`typename remove_reference<Data>::type`]] 1734[[`expr_param`][`typename add_reference<typename add_const<Expr>::type>::type`]] 1735[[`state_param`][`typename add_reference<typename add_const<State>::type>::type`]] 1736[[`data_param`][`typename add_reference<typename add_const<Data>::type>::type`]] 1737] 1738 1739You'll notice that `_child_c::impl::operator()` takes arguments of types `expr_param`, `state_param`, and `data_param`. The typedefs make it easy to accept arguments by reference or const reference accordingly. 1740 1741The only other interesting bit is the `is_callable<>` specialization, which will be described in the [link boost_proto.users_guide.back_end.expression_transformation.is_callable next section]. 1742 1743[endsect] 1744 1745[/=================================================] 1746[section:is_callable Making Your Transform Callable] 1747[/=================================================] 1748 1749Transforms are typically of the form `proto::when< Something, R(A0,A1,...) >`. The question is whether `R` represents a function to call or an object to construct, and the answer determines how _when_ evaluates the transform. _when_ uses the `proto::is_callable<>` trait to disambiguate between the two. Proto does its best to guess whether a type is callable or not, but it doesn't always get it right. It's best to know the rules Proto uses, so that you know when you need to be more explicit. 1750 1751For most types `R`, `proto::is_callable<R>` checks for inheritance from `proto::callable`. However, if the type `R` is a template specialization, Proto assumes that it is /not/ callable ['even if the template inherits from `proto::callable`]. We'll see why in a minute. Consider the following erroneous callable object: 1752 1753 // Proto can't tell this defines something callable! 1754 template<typename T> 1755 struct times2 : proto::callable 1756 { 1757 typedef T result_type; 1758 1759 T operator()(T i) const 1760 { 1761 return i * 2; 1762 } 1763 }; 1764 1765 // ERROR! This is not going to multiply the int by 2: 1766 struct IntTimes2 1767 : proto::when< 1768 proto::terminal<int> 1769 , times2<int>(proto::_value) 1770 > 1771 {}; 1772 1773The problem is that Proto doesn't know that `times2<int>` is callable, so rather that invoking the `times2<int>` function object, Proto will try to construct a `times2<int>` object and initialize it will an `int`. That will not compile. 1774 1775[note Why can't Proto tell that `times2<int>` is callable? After all, it inherits from `proto::callable`, and that is detectable, right? The problem is that merely asking whether some type `X<Y>` inherits from `callable` will cause the template `X<Y>` to be instantiated. That's a problem for a type like `std::vector<_value(_child1)>`. `std::vector<>` will not suffer to be instantiated with `_value(_child1)` as a template parameter. Since merely asking the question will sometimes result in a hard error, Proto can't ask; it has to assume that `X<Y>` represents an object to construct and not a function to call.] 1776 1777There are a couple of solutions to the `times2<int>` problem. One solution is to wrap the transform in `proto::call<>`. This forces Proto to treat `times2<int>` as callable: 1778 1779 // OK, calls times2<int> 1780 struct IntTimes2 1781 : proto::when< 1782 proto::terminal<int> 1783 , proto::call<times2<int>(proto::_value)> 1784 > 1785 {}; 1786 1787This can be a bit of a pain, because we need to wrap every use of `times2<int>`, which can be tedious and error prone, and makes our grammar cluttered and harder to read. 1788 1789Another solution is to specialize `proto::is_callable<>` on our `times2<>` template: 1790 1791 namespace boost { namespace proto 1792 { 1793 // Tell Proto that times2<> is callable 1794 template<typename T> 1795 struct is_callable<times2<T> > 1796 : mpl::true_ 1797 {}; 1798 }} 1799 1800 // OK, times2<> is callable 1801 struct IntTimes2 1802 : proto::when< 1803 proto::terminal<int> 1804 , times2<int>(proto::_value) 1805 > 1806 {}; 1807 1808This is better, but still a pain because of the need to open Proto's namespace. 1809 1810You could simply make sure that the callable type is not a template specialization. Consider the following: 1811 1812 // No longer a template specialization! 1813 struct times2int : times2<int> {}; 1814 1815 // OK, times2int is callable 1816 struct IntTimes2 1817 : proto::when< 1818 proto::terminal<int> 1819 , times2int(proto::_value) 1820 > 1821 {}; 1822 1823This works because now Proto can tell that `times2int` inherits (indirectly) from `proto::callable`. Any non-template types can be safely checked for inheritance because, as they are not templates, there is no worry about instantiation errors. 1824 1825There is one last way to tell Proto that `times2<>` is callable. You could add an extra dummy template parameter that defaults to `proto::callable`: 1826 1827 // Proto will recognize this as callable 1828 template<typename T, typename Callable = proto::callable> 1829 struct times2 : proto::callable 1830 { 1831 typedef T result_type; 1832 1833 T operator()(T i) const 1834 { 1835 return i * 2; 1836 } 1837 }; 1838 1839 // OK, this works! 1840 struct IntTimes2 1841 : proto::when< 1842 proto::terminal<int> 1843 , times2<int>(proto::_value) 1844 > 1845 {}; 1846 1847Note that in addition to the extra template parameter, `times2<>` still inherits from `proto::callable`. That's not necessary in this example but it is good style because any types derived from `times2<>` (as `times2int` defined above) will still be considered callable. 1848 1849[endsect] 1850 1851[endsect] 1852 1853[endsect] 1854