
Hi Dave, Your previous post has brought up a very interesting point for me: I tried to completely specify the behaviour of the logic to give the user a chance to fully understand it and make things more transparent. It seems to me I've been "thinking too close to the implementation" and this approach is no good. ANNOTATION: I'll cut your post down to only refer to what still matters based on a conclusion drawn further below. David Abrahams wrote: <snip>
Subtypes? I think you mean argument, optional class target, and return types. These are not (necessarily) "subtypes!" That word has a very specific -- and different -- meaning in computer science.
I see. How about "Component types?" This term should be close enough to common terminology since we are talking about "compound types." Works?
A type supported by this library is completely described by its argument types, return type, class target (if the type is a member pointer), and the following properties:
- decoration (none,pointer,reference,member pointer) - variadicity - cv-qualification of member function pointers - calling convention
Btw: "argument types" or "parameter types?"
You really don't intend to represent cv-qualification of member function pointers as simply the cv-qualification attached to the class type?
I do -- by default! Specifying these tags allows you to set/query either one of them explicitly. Because: ANNOTATION: I use const_member instead of const_ because it's its new name without trailing underscore. It will imply the 'member_pointer' decoration property then. a) is_const< typename class_of<T>::type >::value // precondition: T must be a member function pointer (decomposition) is_function<T,const_member>::value // no precondition (classification) b) mpl::not< is_const< typename class_of<T>::type > >::value // is lengthy is_function<T,non_const_member>::value // is not, plus it's more efficient c) function_type<MemFnPtr,[non_]const_member>::type // remove/add const from member function // NOTE: not specifying the const property in the context means keeping the // qualification of the original type (given the destination type will be a // member function pointer, that is). <snip> >> free_or_static <<
Okay, I understand. That said, the way you are classifying these things is going to cause confusion. There is no distinction between the types of static member functions and the types of free functions.
This name was exchanged because the initial one I used ("unbound") was found to be too unexpressive.
There is only a distinction in how they are declared; once you are dealing with their types, they are the same thing. The name "free_or_static" carries the implication that you have precise (non-wildcard) tags "free" and "static". In my opinion, you should
...and also goes under "known issues", already.
use the terms "member" and "nonmember." A pointer to a static member function is not a member pointer in the C++ type system; that's why my suggested terminology works. So "free_or_static" should be "nonmember."
OK. It's the best so far. Sometimes the easiest solution seams the least obvious (not to mention that 'member' would have needed disambiguation too, caring about static members ;-) )...
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/
"(possibly decorated)" adds nothing. You have already made it clear that function types can be decorated -- or if you haven't, you can't just throw the term in here in parentheses and expect anyone to understand what you mean.
What 'decorated' means was already introduced (by the very first sentence of the documentation, see previous post). Generally I agree. However in this case it /should/ be mentioned because: template<typename T, typename Tag = undecorated> struct is_function; ^^^^^^^^^^^ The default argument, if no tag is given, makes 'is_function' only match function types (standard definition, compatible with TypeTraits). The "code-to-English-mapping" is like this: is_function<T> // "is T a function (not decorated)?" is_function<T,pointer> // "is T a function pointer?" is_function<T,variadic> // "is the function _in_ T variadic?" However, if too confusing I can introduce a version of 'is_function' with a single template parameter, change the name of the current 'is_function' to something else (e.g. "is_function_of_kind" -- better names are very welcome) and change its default argument. See: http://lists.boost.org/boost/2005/06/29480.php <snip>
Ah sorry, no I was just in a hurry. Make the final sentence of the paragraph:
The specialization of tag used below indicates that the resulting function type should be a pointer to a variadic function.
It's bought. With the first "function" removed, though. <snip>
// Member function pointer -> function with default calling convention function_type<T, tag<undecorated,unspecified_call> >::type
Oh, wait. This use of "unspecified" is very bad, because it conflicts with the very specific way the C++ standard (and many Boost libraries as a result) use the word. The calling convention of the result isn't unspecified -- that would mean "it will be something whose properties we might describe but we're not going to tell you exactly what it is."
This issue was already expressed and "any" was proposed instead.
In this case the calling convention is very much being specified to be the default!
For this purpose, the proper name is "default_call."
Well "default_call" should not be a wildcard then. In classification context "default_call" should mean "detect whether this has default calling convention" (I had to think a moment about if these semantics are implementable -- they are). OK -- STOP. Can we remove the fully-general wildcards for each property from the interface, then? I believe we can: Classification: If you want to ignore a property just don't specify it in the query. Requirements: one wildcard to match any decoration /or/ to change the default argument of the class template currently called 'is_function' (as described above) Synthesis: You either override defaults or properties of an existing type. Requirements: there is a (in some ways special) 'default_call' calling convention.
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,
Allow what?
Sorry: "allow overriding of tag properties".
however, it maybe makes things more complicated to explain (see
<- (because it has to be documented anyway)
below) and involves more template instantiations - so I'm not sure it's really worth it.
<snip>
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.
Yes, the behavior should be documented, but the way you are describing it exposes implementation details and complicates understanding. If you just say that "any properties of the first argument that are not overridden by the second argument will be properties of the result" then you don't need to introduce new jargon for "implicit tag combination."
Very nice! I believe it makes sense move this sentence to the part of the reference section on 'function_type' or 'tag'. Thank you very much for these comments! I'll reassmeble our points to a piece of documentation and post them later.