early-access version 3088

This commit is contained in:
pineappleEA
2022-11-05 15:35:56 +01:00
parent 4e4fc25ce3
commit b601909c6d
35519 changed files with 5996896 additions and 860 deletions

View File

@@ -0,0 +1,35 @@
[/==============================================================================
Copyright (C) 2001-2010 Joel de Guzman
Copyright (C) 2001-2005 Dan Marsden
Copyright (C) 2001-2010 Thomas Heller
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 Arguments]
Arguments are also functions? You bet!
Until now, we have been dealing with expressions returning a nullary function.
Arguments, on the other hand, evaluate to an N-ary function. An argument
represents the Nth argument. There are a few predefined arguments arg1,
arg2, arg3, arg4 and so on (and it's __bll__ counterparts: _1, _2, _3, _4 and so
on). Examples:
arg1 // one-or-more argument function that returns its first argument
arg2 // two-or-more argument function that returns its second argument
arg3 // three-or-more argument function that returns its third argument
`argN` returns the Nth argument. Examples:
int i = 3;
char const* s = "Hello World";
std::cout << arg1(i) << std::endl; // prints 3
std::cout << arg2(i, s) << std::endl; // prints "Hello World"
(See [@../../example/arguments.cpp arguments.cpp])
[blurb __tip__ Learn more about arguments [link phoenix.modules.core.arguments here.]]
[endsect]

View File

@@ -0,0 +1,63 @@
[/==============================================================================
Copyright (C) 2001-2010 Joel de Guzman
Copyright (C) 2001-2005 Dan Marsden
Copyright (C) 2001-2010 Thomas Heller
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 Lazy Functions]
As you write more lambda functions, you'll notice certain patterns that you wish
to refactor as reusable functions. When you reach that point, you'll wish that
ordinary functions can co-exist with phoenix functions. Unfortunately, the
/immediate/ nature of plain C++ functions make them incompatible.
Lazy functions are your friends. The library provides a facility to make lazy
functions. The code below is a rewrite of the `is_odd` function using the
facility:
struct is_odd_impl
{
typedef bool result_type;
template <typename Arg>
bool operator()(Arg arg1) const
{
return arg1 % 2 == 1;
}
};
function<is_odd_impl> is_odd;
[heading Things to note:]
[/
* `result` is a nested metafunction that reflects the return type of the
function (in this case, bool). This makes the function fully polymorphic:
It can work with arbitrary `Arg` types.
* There are as many Args in the `result` metafunction as in the actual
`operator()`.
]
* Result type deduction is implemented with the help of the result_of protocol.
For more information see __boost_result_of__
* `is_odd_impl` implements the function.
* `is_odd`, an instance of `function<is_odd_impl>`, is the lazy function.
Now, `is_odd` is a truly lazy function that we can use in conjunction with the
rest of phoenix. Example:
std::find_if(c.begin(), c.end(), is_odd(arg1));
(See [@../../example/function.cpp function.cpp])
[heading Predefined Lazy Functions]
The library is chock full of STL savvy, predefined lazy functions covering the
whole of the STL containers, iterators and algorithms. For example, there are lazy
versions of container related operations such as assign, at, back, begin,
pop_back, pop_front, push_back, push_front, etc. (See [link phoenix.modules.stl
STL]).
[endsect]

View File

@@ -0,0 +1,21 @@
[/==============================================================================
Copyright (C) 2001-2010 Joel de Guzman
Copyright (C) 2001-2005 Dan Marsden
Copyright (C) 2001-2010 Thomas Heller
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 More]
As mentioned earlier, this chapter is not a thorough discourse of the library.
It is meant only to cover enough ground to get you into high gear as quickly as
possible. Some advanced stuff is not discussed here (e.g. [link phoenix.modules.scope
Scopes]); nor are features that provide alternative (short-hand) ways to do the
same things (e.g. [link phoenix.modules.bind Bind] vs. [link phoenix.modules.function Lazy Functions]).
[blurb __tip__ ...*If you still wish to learn more, the read on...*]
[endsect]

View File

@@ -0,0 +1,26 @@
[/==============================================================================
Copyright (C) 2001-2010 Joel de Guzman
Copyright (C) 2001-2005 Dan Marsden
Copyright (C) 2001-2010 Thomas Heller
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 Construct, New, Delete, Casts]
You'll probably want to work with objects. There are lazy versions of
constructor calls, `new`, `delete` and the suite of C++ casts. Examples:
construct<std::string>(arg1, arg2) // constructs a std::string from arg1, arg2
new_<std::string>(arg1, arg2) // makes a new std::string from arg1, arg2
delete_(arg1) // deletes arg1 (assumed to be a pointer)
static_cast_<int*>(arg1) // static_cast's arg1 to an int*
[note Take note that, by convention, names that conflict with C++
reserved words are appended with a single trailing underscore `'_'`]
[blurb __tip__ Learn more about this [link phoenix.modules.object here.]]
[endsect]

View File

@@ -0,0 +1,87 @@
[/==============================================================================
Copyright (C) 2001-2010 Joel de Guzman
Copyright (C) 2001-2005 Dan Marsden
Copyright (C) 2001-2010 Thomas Heller
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 Lazy Operators]
You can use the usual set of operators to form expressions. Examples:
arg1 * arg1
ref(x) = arg1 + ref(z)
arg1 = arg2 + (3 * arg3)
ref(x) = arg1[arg2] // assuming arg1 is indexable and arg2 is a valid index
Note the expression: `3 * arg3`. This expression is actually a short-hand
equivalent to: `val(3) * arg3`. In most cases, like above, you can get away with
it. But in some cases, you will have to explicitly wrap your values in `val`.
Rules of thumb:
* In a binary expression (e.g. `3 * arg3`), at least one of the operands must be
a phoenix primitive or expression.
* In a unary expression (e.g. `arg1++`), the single operand must be a phoenix
primitive or expression.
If these basic rules are not followed, the result is either an error, or is
immediately evaluated. Some examples:
ref(x) = 123 // lazy
x = 123 // immediate
ref(x)[0] // lazy
x[0] // immediate
ref(x)[ref(i)] // lazy
ref(x)[i] // lazy (equivalent to ref(x)[val(i)])
x[ref(i)] // illegal (x is not a phoenix primitive or expression)
ref(x[ref(i)]) // illegal (x is not a phoenix primitive or expression)
Why are the last two expression illegal? Although `operator[]` looks as
much like a binary operator as `operator=` above it; the difference is
that the former must be a member (i.e. `x` must have an `operator[]`
that takes a phoenix primitive or expression as its argument). This will
most likely not be the case.
[blurb __tip__ Learn more about operators [link phoenix.modules.operator here.]]
[heading First Practical Example]
We've covered enough ground to present a real world example. We want to find the
first odd number in an STL container. Normally we use a functor (function
object) or a function pointer and pass that in to STL's `find_if` generic
function:
Write a function:
bool
is_odd(int arg1)
{
return arg1 % 2 == 1;
}
Pass a pointer to the function to STL's `find_if` algorithm:
std::find_if(c.begin(), c.end(), &is_odd)
Using Phoenix, the same can be achieved directly with a one-liner:
std::find_if(c.begin(), c.end(), arg1 % 2 == 1)
The expression `arg1 % 2 == 1` automagically creates a functor with the expected
behavior. In FP, this unnamed function is called a lambda function. Unlike the
function pointer version, which is monomorphic (expects and works only with a
fixed type int argument), the Phoenix version is fully polymorphic and works
with any container (of ints, of longs, of bignum, etc.) as long as its elements
can handle the `arg1 % 2 == 1` expression.
(See [@../../example/find_if.cpp find_if.cpp])
[blurb __tip__ ...[*That's it, we're done]. Well if you wish to know a little bit
more, read on...]
[endsect]

View File

@@ -0,0 +1,31 @@
[/==============================================================================
Copyright (C) 2001-2010 Joel de Guzman
Copyright (C) 2001-2005 Dan Marsden
Copyright (C) 2001-2010 Thomas Heller
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 References]
References are functions. They hold a reference to a value stored somewhere.
For example, given:
int i = 3;
char const* s = "Hello World";
we create `references` to `i` and `s` this way:
ref(i)
ref(s)
Like `val`, the expressions above evaluates to a nullary function; the first one
returning an `int&`, and the second one returning a `char const*&`.
(See [@../../example/references.cpp references.cpp])
[blurb __tip__ Learn more about references [link phoenix.modules.core.references here.]]
[endsect]

View File

@@ -0,0 +1,34 @@
[/==============================================================================
Copyright (C) 2001-2010 Joel de Guzman
Copyright (C) 2001-2005 Dan Marsden
Copyright (C) 2001-2010 Thomas Heller
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 Lazy Statements]
Lazy statements? Sure. There are lazy versions of the C++ statements we all know
and love. For example:
if_(arg1 > 5)
[
std::cout << arg1
]
Say, for example, we wish to print all the elements that are greater than 5
(separated by a comma) in a vector. Here's how we write it:
std::for_each(v.begin(), v.end(),
if_(arg1 > 5)
[
std::cout << arg1 << ", "
]
);
(See [@../../example/if.cpp if.cpp])
[blurb __tip__ Learn more about statements [link phoenix.modules.statement here.]]
[endsect]

View File

@@ -0,0 +1,67 @@
[/==============================================================================
Copyright (C) 2001-2010 Joel de Guzman
Copyright (C) 2001-2005 Dan Marsden
Copyright (C) 2001-2010 Thomas Heller
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 Values]
Values are functions! Examples:
val(3)
val("Hello, World")
The first evaluates to a nullary function (a function taking no arguments) that
returns an `int`, `3`. The second evaluates to a nullary function that returns
a `char const(&)[13]`, `"Hello, World"`.
[heading Lazy Evaluation]
Confused? `val` is a unary function and `val(3)` invokes it, you say?
Yes. However, read carefully: /"evaluates to a nullary function"/.
`val(3)` evaluates to (returns) a nullary function. Aha! `val(3)`
returns a function! So, since `val(3)` returns a function, you can
invoke it. Example:
std::cout << val(3)() << std::endl;
(See [@../../example/values.cpp values.cpp])
[blurb __tip__ Learn more about values [link phoenix.modules.core.values here.]]
The second function call (the one with no arguments) calls the nullary function
which then returns `3`. The need for a second function call is the reason why
the function is said to be [*/Lazily Evaluated/]. The first call doesn't do
anything. You need a second call to finally evaluate the thing. The first call
lazily evaluates the function; i.e. doesn't do anything and defers the evaluation
for later.
[heading Callbacks]
It may not be immediately apparent how lazy evaluation can be useful by just
looking at the example above. Putting the first and second function call in a
single line is really not very useful. However, thinking of `val(3)` as a
callback function (and in most cases they are actually used that way), will make
it clear. Example:
template <typename F>
void print(F f)
{
cout << f() << endl;
}
int
main()
{
print(val(3));
print(val("Hello World"));
return 0;
}
(See [@../../example/callback.cpp callback.cpp])
[endsect]