
Hi Dave, David Abrahams wrote:
Tobias Schwinger <tschwinger@neoscientists.org> writes:
Let's try this again:
Thanks for your rewrite. I hope it gives us a starting point to finally straighten this section, which seems quite tricky to document and I really can use any help with it!
Tag Types ----------
The Function Types library uses *tag* types to represent or query one or more properties of a type, such as its variadicness, or whether it is a pointer.
The "kind" term from the previos version was meant to be defined in a more global place. Like this: A type supported by this library is completely described by its subtypes and its kind. The kind collectively refers to the following information: - decoration (none,pointer,reference,member pointer) - variadicity - cv-qualification of member function pointers - the calling convention attribute Actually it is very helpful - not only for this part. Maybe reintroduce it?
Tags that represent the values of a single property are called *property tags*. These tags can be used to determine whether one property of the type has a particular value.
is_function< T, variadic > is_function< T, pointer > // same as is_function_pointer<T>
To match against several values of a property at once, you can use wildcard property tags:
"Wildcard" requires the context of classification to fit perfectly...
is_function< T, free_or_static >
// the tag 'free_or_static' captures two values of the decoration // property and makes the above code equivalent to:
mpl::or_< is_function_type< T, undecorated> , is_function_type< T, pointer > , is_function_type< T, reference > >
[?? This example doesn't make any sense to me; what do "undecorated," "pointer," and "reference" have to do with whether a function is free or static?? If you really meant what you wrote, you had better explain -- at length!]
The very first sentence descibing the library in a whole introduces it (this has not been posted yet). I'm not sure it is sufficient, though: Overview This library provides functionality to classify, decompose and synthesize function types and other compound types directly decorating a function type with a pointer, reference or member pointer. So the idea behind the decoration property is this: Given a function type F F is undecorated \ F* is pointer decorated - free or static decoration ("wildcard") F& is reference decorated / C::*F is member-pointer-decorated The reference shows this grouping, too. Unfortunately the "[/ FIXME: add link to reference ]" at the point where the "aspect tags" are introduced got lost (because I copied from the browser instead of my .qbk master file).
Every property has a fully-general wildcard tag that can be used to indicate that /any/ value of the property should be matched. The tag's name is the same as that of the property, but with the prefix "unspecfied_".
is_function< T, unspecified_decoration >::value // true for any type T that the library can handle
[You need to say more clearly what "can handle" means. IMO the comment should really be expressed as the last sentence of the foregoing paragraph]
s/type the library can handle/(possibly decorated) function type/
Each abstract variation of an aspect has a non-abstract semantic equivalence
Wha??? I don't know how to translate that into something simpler, because I can't tell what it means!
It means that wildcards in fact are abstract ;-) and undergo a process of "automatic concretization" in the context of type synthesis. This does not directly give us a use case but is essential to understaning the logic because it allows us to write: function_type< mpl::vector<int,int>, pointer >::type What happens here is: all properties other than the decoration property default to unspecified_*. These are "concretized" (in this context -- we need a concrete description for creating a type) to produce a pointer to a non-variadic function of the default calling convention. Because of this "concretization", the same tag expressions work for both classification and synthesis: is_function<F,pointer>::value Here ^^^ we ignore anything except the decoration property.
when used in the context of type synthesis (as defined in the reference section).
function_type<void(X::*)(), free_or_static>::type
// is equivalent to:
function_type<void(X::*)(), undecorated>::type
And the example doesn't help me tell what it means, mostly because of my confusion above, probably.
As I said: it does not directly give a use case. So the "examples" are in fact "demonstrations of behaviour" fundamental to the logic.
A tag created from a type completely describes all aspects of the type's kind. The aspect variations in the tag are never abstract.
signature< void() > // describes all aspects: undecorated, non-variadic, ...
A signature tag is a compound tag that precisely describes all of a specific type's properties, so it does not act as a wildcard.
signature< void() > // describes all aspects: undecorated, non-variadic, ...
[This example fails to illustrate your main point, which is that it doesn't act as a wildcard. That said, I'm not sure it's an important point to make -- it should be obvious! Anyway, if you use this section it should come after compound property tags are introduced below]
Agreed. I wasn't to happy about its placement either. By the way: signature<F> // is model of: Tag & Front-/Back Extensible/Random Access MPL Sequence
When classifying and especially when synthesising types, there are situations in which it is neccessary to describe more than one aspect. Therefore tags can be combined using the tag metafunction.
function_type< mpl::vector<int,int>, tag<pointer,variadic> >::type // is int(*)(int...)
[That "tag" template is not obviously a metafunction from its usage. I believe calling it that here (even if it really is one) is confusing. ]
OK. In fact I plan to document a Tag concept.
A compound property tag describes a combination of possible values of different properties. The tag class template can be used to create a specific compound property tag. The specialization of tag used below matches all pointers to variadic functions, and the type vector further restricts the type matched to int(*)(int,...).
Hmm... I'm having difficulties combining this ^^ text with this VV example.
function_type< mpl::vector<int,int>, tag<pointer,variadic> >::type
^^ this creates a function pointer, not a tag The example was not sufficiently documented, I guess. Sorry!!!
In the context of classification all aspects represented by the query tag must match:
A compound property tag matches a type only when all of its component properties match:
It's not restricted to matching types. It's also possible to match other tags. That's why I used the words I did. However, inserting "or another tag" does fix it, I believe.
is_function_type< void(...), tag<free_or_static,variadic> >::value // is true
is_function_type< void(X::*)(...), tag<free_or_static,variadic> >::value // is false
Except for tag combination, each aspect that is not represented by a tag is similar to the abstract variation represented by the tag named "unspecified_" plus that aspect's name. This is why these tags do not have to be specified in many contexts.
[I don't know what "except for tag combination" is supposed to mean above, so I left it out below, but if it's important, you need to describe what _does_ happen when you use the fully-general wildcard in a "tag combination" (whatever that is)]
"Tag combination" was supposed to mean: "tag<T1,T2>". What does happen is what happens for all properties described in the next paragraph.
The fully-general wildcard tag for any property not otherwise represented can be added to a tag specialization without changing its meaning.
It's not entirely true (and what I was trying to say), because: typedef tag< variadic, unspecified_decoration > X; typedef variadic Y; tag< pointer /* <-- gets overridden */ , X > tag< pointer /* <-- does not get overridden */ , Y > So X and Y have different meanings but it won't matter unless they are used to (explicitly or implicitly) form another compound tag.
[Now that I read it I guess I don't know whether I am even saying what you were trying to say here. And I don't know what use the 2nd sentence (which needs an antecedent for "this") is without an example]
When there are tags representing different variations of the same aspect in tag's template argument list, the last variation is used; others are ignored.
When several tags for the same property appear in the argument list, only the last one is used; others are ignored.
[I assume we are still on the topic of the "tag" class template here, so "the argument list" is sufficient. I wonder if there's a rationale for this behavior, as opposed to making it a compile-time error?]
Oh yes. Try these: // a remove constness (of the pointee) from a member function pointer type T function_type<T, non_const >::type or // create a (possibly decorated) function type's variadic version function_type<T, variadic >::type or // Member function pointer -> function with default calling convention function_type<T, tag<undecorated,unspecified_call> >::type Here the properties of the original types are overridden in an implicit tag combination with the tag representing the type. Well, we /could/ only allow it in this very context, however, it maybe makes things more complicated to explain (see below) and involves more template instantiations - so I'm not sure it's really worth it.
tag<free_or_static,reference> // decoration aspect is 'reference'
tag<reference,undecorated> // decoration aspect is 'undecorated'
tag<undecorated,reference,unspecified_decoration> // decoration aspect is 'unspecified_decoration'
tag<undecorated,variadic,pointer> // two aspects are set: pointer decoration and variadic
Tag combination occurs either explicitly by using the tag metafunction or implicitly. Implicit tag combination takes place when using function_type with a tag or (possibly decorated) function type as its first template argument.
Tags can be combined either explicitly, by using the tag metafunction, or implicitly. Implicit tag combination takes place when function_type is used with a tag or function type as its first template argument. In the example below, any properties of the first argument to function_type not overridden by those in the tag specialization are turned into a tag and implicitly combined with the tag specialization to produce a new function type.
[personally I don't believe it's important for users to know that implicit tag combination happens here, and I think saying so just complicates matters. It would be just as useful to say that "any properties represented in the tag specialization override those of the first argument to produce a new function type," and leave it at that.]
No? function_type< my_mpl_sequence, pointer > // no implicit tag combination VVVVV function_type< my_function , pointer > // implicit tag combination function_type< signature<F> , pointer > // implicit tag combination ^^^^^ I believe it is _very_ important to document this behaviour.
function_type<void __cdecl(X::*)(),tag<undecorated,unspecified_call> > // ::type member is 'void(my_class&)' // the decoration and calling convention aspect are overridden
Thanks, Tobias