mirror of
https://github.com/boostorg/proto.git
synced 2026-01-29 19:52:15 +00:00
216 lines
7.8 KiB
Plaintext
216 lines
7.8 KiB
Plaintext
[/
|
|
/ Copyright (c) 2008 Eric Niebler
|
|
/
|
|
/ Distributed under the Boost Software License, Version 1.0. (See accompanying
|
|
/ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
|
/]
|
|
|
|
[section:release_notes Appendix A: Release Notes]
|
|
|
|
[/=================]
|
|
[heading Boost 1.44]
|
|
[/=================]
|
|
|
|
[*Behavior Change: proto::and_<>]
|
|
|
|
In Boost 1.44, the behavior of _and_ as a transform changed. Previously, it only
|
|
applied the transform associated with the last grammar in the set. Now, it applies
|
|
all the transforms but only returns the result of the last. That makes it behave
|
|
like C++'s comma operator. For example, a grammar such as:
|
|
|
|
proto::and_< G0, G1, G2 >
|
|
|
|
when evaluated with an expression `e` now behaves like this:
|
|
|
|
(G0()(e), G1()(e), G2()(e))
|
|
|
|
[*Behavior Change: proto::as_expr() and proto::as_child()]
|
|
|
|
The functions _as_expr_ and _as_child_ are used to guarantee that an
|
|
object is a Proto expression by turning it into one if it is not already,
|
|
using an optionally specified domain. In previous releases, when these
|
|
functions were passed a Proto expression in a domain different to the one
|
|
specified, they would apply the specified domain's generator, resulting in
|
|
a twice-wrapped expression. This behavior was surprising to some users.
|
|
|
|
The new behavior of these two functions is to always leave Proto expressions
|
|
alone, regardless of the expressions' domains.
|
|
|
|
[*Behavior Change: proto::(pod_)generator<> and proto::basic_expr<>]
|
|
|
|
Users familiar with Proto's extension mechanism have probably used either
|
|
_generator_ or _pod_generator_ with a wrapper template when defining their
|
|
domain. In the past, Proto would instantiate your wrapper template with
|
|
instances of _expr_. In Boost 1.44, Proto now instantiates your wrapper
|
|
template with instances of a new type: _basic_expr_.
|
|
|
|
For instance:
|
|
|
|
// An expression wrapper
|
|
template<class Expr>
|
|
struct my_expr_wrapper;
|
|
|
|
// A domain
|
|
struct my_domain
|
|
: proto::domain< proto::generator< my_expr_wrapper > >
|
|
{};
|
|
|
|
template<class Expr>
|
|
struct my_expr_wrapper
|
|
: proto::extends<Expr, my_expr_wrapper<Expr>, my_domain>
|
|
{
|
|
// Before 1.44, Expr was an instance of proto::expr<>
|
|
// In 1.44, Expr is an instance of proto::basic_expr<>
|
|
};
|
|
|
|
The motivation for this change was to improve compile times. _expr_ is an
|
|
expensive type to instantiate because it defines a host of member functions.
|
|
When defining your own expression wrapper, the instance of _expr_ sits as a
|
|
hidden data member function in your wrapper and the members of _expr_ go
|
|
unused. Therefore, the cost of those member functions is wasted. In contrast,
|
|
_basic_expr_ is a very lightweight type with no member functions at all.
|
|
|
|
The vast majority of programs should recompile without any source changes.
|
|
However, if somewhere you are assuming that you will be given instances
|
|
specifically of _expr_, your code will break.
|
|
|
|
[*New Feature: Sub-domains]
|
|
|
|
In Boost 1.44, Proto introduces an important new feature called
|
|
"sub-domains". This gives you a way to spcify that one domain is
|
|
compatible with another such that expressions in one domain can
|
|
be freely mixed with expressions in another. You can define one
|
|
domain to be the sub-domain of another by using the third template
|
|
parameter of _domain_.
|
|
|
|
For instance:
|
|
|
|
// Not shown: define some expression
|
|
// generators genA and genB
|
|
|
|
struct A
|
|
: proto::domain< genA, proto::_ >
|
|
{};
|
|
|
|
// Define a domain B that is the sub-domain
|
|
// of domain A.
|
|
struct B
|
|
: proto::domain< genB, proto::_, A >
|
|
{};
|
|
|
|
Expressions in domains `A` and `B` can have different wrappers
|
|
(hence, different interfaces), but they can be combined into larger
|
|
expressions. Without a sub-domain relationship, this would have
|
|
been an error. The domain of the resulting expression in this case
|
|
would be `A`.
|
|
|
|
The complete description of sub-domains can be found in the reference
|
|
sections for _domain_ and _deduce_domain_.
|
|
|
|
[*New Feature: Domain-specific as_expr() and as_child()]
|
|
|
|
Proto has always allowed users to customize expressions post-hoc by
|
|
specifying a Generator when defining their domain. But it has never
|
|
allowed users to control how Proto assembles sub-expressions in the
|
|
first place. As of Boost 1.44, users now have this power.
|
|
|
|
Users defining their own domain can now specify how _as_expr_ and
|
|
_as_child_ work in their domain. They can do this easily by defining
|
|
nested class templates named `as_expr` and/or `as_child` within their
|
|
domain class.
|
|
|
|
For example:
|
|
|
|
struct my_domain
|
|
: proto::domain< my_generator >
|
|
{
|
|
typedef
|
|
proto::domain< my_generator >
|
|
base_domain;
|
|
|
|
// For my_domain, as_child does the same as
|
|
// what as_expr does by default.
|
|
template<class T>
|
|
struct as_child
|
|
: base_domain::as_expr<T>
|
|
{};
|
|
};
|
|
|
|
In the above example, `my_domain::as_child<>` simply defers to
|
|
`proto::domain::as_expr<>`. This has the nice effect of causing
|
|
all terminals to be captured by value instead of by reference,
|
|
and to likewise store child expressions by value. The result is
|
|
that expressions in `my_domain` are safe to store in `auto`
|
|
variables because they will not have dangling references to
|
|
intermediate temporary expressions. (Naturally, it also means that
|
|
expression construction has extra runtime overhead of copying that
|
|
the compiler may or may not be able to optimize away.)
|
|
|
|
[/=================]
|
|
[heading Boost 1.43]
|
|
[/=================]
|
|
|
|
In Boost 1.43, the recommended usage of _extends_ changed slightly. The new
|
|
usage looks like this:
|
|
|
|
// my_expr is an expression extension of the Expr parameter
|
|
template<typename Expr>
|
|
struct my_expr
|
|
: proto::extends<Expr, my_expr<Expr>, my_domain>
|
|
{
|
|
my_expr(Expr const &expr = Expr())
|
|
: proto::extends<Expr, my_expr, my_domain>(expr)
|
|
{}
|
|
|
|
// NEW: use the following macro to bring
|
|
// proto::extends::operator= into scope.
|
|
BOOST_PROTO_EXTENDS_USING_ASSIGN(my_expr)
|
|
};
|
|
|
|
The new thing is the use of the [^[macroref BOOST_PROTO_EXTENDS_USING_ASSIGN]()] macro.
|
|
To allow assignment operators to build expression trees, _extends_ overloads the
|
|
assignment operator. However, for the `my_expr` template, the compiler generates
|
|
a default copy assignment operator that hides the ones in _extends_. This is often
|
|
not desired (although it depends on the syntax you want to allow).
|
|
|
|
Previously, the recommended usage was to do this:
|
|
|
|
// my_expr is an expression extension of the Expr parameter
|
|
template<typename Expr>
|
|
struct my_expr
|
|
: proto::extends<Expr, my_expr<Expr>, my_domain>
|
|
{
|
|
my_expr(Expr const &expr = Expr())
|
|
: proto::extends<Expr, my_expr, my_domain>(expr)
|
|
{}
|
|
|
|
// OLD: don't do it like this anymore.
|
|
using proto::extends<Expr, my_expr, my_domain>::operator=;
|
|
};
|
|
|
|
While this works in the majority of cases, it still doesn't suppress the
|
|
implicit generation of the default assignment operator. As a result, expressions
|
|
of the form `a = b` could either build an expression template or do a copy
|
|
assignment depending on whether the types of `a` and `b` happen to be the
|
|
same. That can lead to subtle bugs, so the behavior was changed.
|
|
|
|
The [^[macroref BOOST_PROTO_EXTENDS_USING_ASSIGN]()] brings into scope the
|
|
assignment operators defined in _extends_ as well as suppresses the generation
|
|
of the copy assignment operator.
|
|
|
|
Also note that the _literal_ class template, which uses _extends_, has been chaged
|
|
to use [^[macroref BOOST_PROTO_EXTENDS_USING_ASSIGN]()]. The implications are
|
|
highlighted in the sample code below:
|
|
|
|
proto::literal<int> a(1), b(2); // two non-const proto literals
|
|
proto::literal<int> const c(3); // a const proto literal
|
|
|
|
a = b; // No-op. Builds an expression tree and discards it.
|
|
// Same behavior in 1.42 and 1.43.
|
|
|
|
a = c; // CHANGE! In 1.42, this performed copy assignment, causing
|
|
// a's value to change to 3. In 1.43, the behavior is now
|
|
// the same as above: build and discard an expression tree.
|
|
|
|
[endsect]
|