10.4. C++ as the Host Language
Fortunately for us, C++ turns out to be a one-of-a-kind language for implementing DSELs. Its multiparadigm heritage has left C++ bristling with tools we can use to build libraries that combine syntactic expressivity with runtime efficiency. In particular, C++ provides
A static type system The ability to achieve near-zero abstraction penalty Powerful optimizers A template system that can be used to generate new types and functions perform arbitrary computations at compile time dissect existing program components (e.g., using the type categorization metafunctions of the Boost Type Traits library)
A macro preprocessor providing (textual) code generation capability orthogonal to that of templates (see Appendix A) A rich set of built-in symbolic operators (48!)many of which have several possible spellingsthat can be overloaded with practically no limitations on their semantics
Table 10.1 lists the syntactic constructs provided by operator overloading in C++. Table entries with several lines show some little-known alternative spellings for the same tokens.
Table 10.1. C++ Overloadable Operator Syntaxes+a | -a | a + b | a - b | ++a | --a | a++ | a-- | a * b | a / b | a % b | a, b | a & b a bitand b | a | b a bitor b | a ^ b a ??' b a xor b | ~a ??-a compl a | a & & b a and b | a | | b a or b | a >> b | a << b | a > b | a < b | a >= b | a <= b | a == b | a != b a not_eq b | ! a not a | a = b | a += b | a -= b | a *= b | a /= b | a %= b | a &= b a and_eq b | a |= b a or_eq b | a ^= b a xor_eq b | a >>= b | a <<= b | *a | &a | a->name | a->*name | a [b] a?? (b??) a<:b:> | a (arguments) | new ctor-expr | delete a | | |
The unique combination of these features in C++ has made possible a category of domain-specific libraries that are both efficient and syntactically close to languages one might build from scratch. Moreover, these libraries can be written in pure C++, giving them important advantages over standalone DSLs, which require special compilers, editors, and other tools. In the following sections we'll discuss some examples, in each case focusing on the DSL's design rather than its implementation.
Until now, we've been fairly disciplined about always prefixing names from namespace boost with boost:: and names from boost::mpl with mpl:: to avoid confusion. In this chapter only, to emphasize the "sugary" aspects of DSL syntax, we're going to omit namespace names from library identifiers, and trust you to guess where the names come from.
|
|