
Rob Stewart wrote:
From: Tobias Schwinger <tschwinger@neoscientists.org>
Documentation preview (includes three sections):
http://tinyurl.com/dg68y (not yet hyperlinked)
________________________________
Overview
Boost.FunctionTypes provides functionality to classify, decompose and synthesize function types and other compound types such as
^^^ ^^^ A prime example of why one really should always use the extra comma in a series. There can be no confusion when you do so.
...classify, decompose, and synthesize function types and other....
OK.
pointer-, reference- and pointer to member function types.
I don't get what "pointer-" and "reference-" are supposed to be joined with to make that phrase work. There are function pointer types and function reference types, but there are no "pointer-function types" or "reference-function types."
OK.
I'm assuming you meant this:
...types such as function pointer, function reference, and member function pointer types.
This means in other words to
This means you can
> * test whether a type is a specific callable builtin type,
...specific, callable, built-in type;
Note the trailing semicolon. Since some items in your list have commas, you need to use semicolons to separate the list items.
For all of them or just for the one with the commas?
Note also that "builtin" should be "built-in."
> * inspect function properties such as arity, kind, result- and parameter types, and
You haven't defined "kind," so it's not helpful here.
Right. It's an artefact.
What's "result-" supposed to connect to?
'types', however it seems English lacks this feature to enumerate compound words with a common ending ;-).
* inspect function properties such as arity, result type, parameter types, etc.; and
> * create callable builtin types from specified function properties.
...callable, built-in types....
OK.
it specializes in the manifold properties of callable builtin types.
As someone else wrote, "manifold properties" is almost inscrutable to me. While the usage is correct, the word is rarely used as an adjective.
Ahh! Now I fully understand what's wrong with this sentence!
s/builtin/built-in/
it specializes in the many properties of callable built-in types.
How about ... specializes in callable, built-in types. ??
_____________________________________
Introduction
About 300 overloads are needed for three different calling conventions and a maximum arity of 10. This calculation is
You haven't mentioned "calling conventions" before this. Shouldn't that be in the table?
It /is/ there. Did you perhaps overlook it in the table?
simplified and more irregular in reality.
s/and more/and is more/
OK.
* it can lead to a noticable slowdown,
* can be slower,
Slower than what?
(If not, fix the spelling of "noticeable.")
OK. I'll go with this one.
This is why Boost.FunctionTypes factors it out and allows
^^ Missing antecendent.
OK.
client code to arbitrarily classify and decompose any of the type's multi-faceted properties:
Boost.FunctionTypes addresses those disadvantages and allows your code to arbitrarily classify and decompose any of a function type's properties. The example becomes much simpler as the function template's template argument list and formal parameter type are reduced to "T":
The beginning is good. It's still too lengthy for my taste. Btw: simpler than what?
It can be desirable to transform callable built-in types. This
In other situations, you may need to transform from one callable built-in type to another.
I try to avoid 2nd person singular except for "please note blocks." Another situation is to ... Isn't that "from one to another"-thing implied by "tranform?"
is especially useful together with Boost.Function. The next example shows specializing boost::function to store an arbitrary callable scalar f of type F.
This example illustrates how to specialize boost::function to store an arbitrary, callable scalar f of type F:
Nice!
The example for that should really build upon the previous example:
template<typename F> void facility::register_function(F f) { boost::function<typename function_type<F>::type> wrapped = f; // call wrapped as appropriate }
It's intentional because it makes little sense in this context: You'ld usually want to do declare the boost::function at class scope (of a different class). More details on this issue can be found below.
An opportunity for optimization is to transform the signature changing by-value parameters to use constant references to avoid duplicate copy-construction when the boost::function object's parentheses operator is called (the fact that adding a reference can be inefficient for small sized objects is ignored for the sake of simplicity here).
Too long and missing at least a comma. It also doesn't guide the reader enough.
A common optimization, when forwarding parameters from one function to another, is to transform by-value parameters to references to const. This avoids creating superfluous copies when one function calls another.
Great!
In our example, if register_function() takes the argument types from its template argument F and uses them to declare the boost::function object f. If F includes by-value parameters, then register_function() will create superfluous copies of its arguments when calling f. Ideally, we want f to take its arguments by reference to const to avoid those copies. (For simplicity's sake, we ignore the fact that passing by-value is more efficient for small objects.)
Unfortunately, optimized_prototype doesn't help one understand how this technique applies to register_function().
OK. I had an invocation for this metafunction in there once... Seems it accidently got cut away ;-(.
As you can now see, I think you should develop register_function() as you go along so the reader can see the reason for each aspect for which Boost.FunctionTypes can offer help.
As stated above it's not that easy and would require more infrastructure around the examples. Previous example: template<typename T> void facility::register_function(T a) { < // [...] <-- use Boost.FunctionTypes on T
BOOST_MPL_ASSERT_MSG(is_callable_scalar<T>::value ,NO_CALLABLE_SCALAR_TYPE, (T)); this->callback = action<T>(a); // <-- uses Boost.FunctionTypes on T }
Then: template<typename F> class action { boost::function<typename function_type<F>::type> wrapped; action(F f) : wrapped(f) // ... }; Well, what I don't like about it (besides that there's more infrastructure around the actual thing) is that both are not necessarily the same case. I'm not feeling too strong about it, though (at least when there are headlines for every use case).
When taking the address of an overloaded function or function template, the type of the function must be told to the compiler.
This part seems abrubtly different from the preceding text and examples. Does it fit with register_function() somehow or is it unrelated?
Actually, all three are different.
If the latter, might I suggest that you delineate that separation?
I'ld have to add a headline for all of them (I wanted to do so but failed finding good titles so I left it out, for now).
IOW, develop register_function() as far as you can using Boost.FunctionTypes facilities. When that example runs dry, move on to a new section and discuss the other facilities of the library with new examples.
"Must be told to the compiler" is awkward at best.
...you must give the function's type to the compiler.
OK.
Boost.FunctionTypes can help automating it.
Fortunately, Boost.FunctionTypes can help to automate those cases:
Not sure about the "fortunately" -- the rest of it is bought.
The above metafunction can be used to create a situation similar to the third trivial example above in a nondeduced context of a function template like the following.
function_pointer_helper can now be used to simplify <something>....
Good.
"The third trivial example above in a nondeduced context of a function template" is practically useless. One has to work so hard to grok that phrase that one is unlikely to do it, so the example isn't likely to be of much value.
What would be useful is to show exactly how to solve the std::for_each example.
The problem is that you won't need the library for the std::for_each example.
Don't leave more than necessary as an exercise for the reader. This is the introduction and you want to show how your library is actually used to solve real problems.
feed_tuple_to_function references "Fusion" tuples. I presume those are part of the project under development for Boost that has yet to be accepted (so far as I recall). Why introduce what is likely to be foreign to many readers in your introduction?
It's a sub library of Boost.Spirit since Boost 1.31 (Fusion as a stand-alone library has yet to accepted, though). You don't have to be too familiar with Fusion to understand what's happening here.
Assuming these delcarations;
s/delcarations;/declarations/
Note that this technique is generally not well-suited to serve as an interface for generic facilities because it has many limitations, such as requiring a known result type and the exact parameter types (rather than types for possible arguments) and because feed_tuple_to_function cannot be overloaded.
After looking at the example and reading that text, I'm left to wonder what value the example offers.
Not everything has to be entirely generic to make sense and not every technique out there is for creating interfaces of generic libraries...
Is it something a person needs to do with any regularity (something I'd expect from a library introduction)?
There's not much regularity in the exact case shown by the example. However overload selection (the principle behind the example) is an important use case and should be shown here. Testing whether a class type contains a particular member function (based on SFINAE and sizeof), is a more regular case but less obvious and depends on tricky techniques that would require off-scope explanation. Thank you very much, Tobias