Note that for compilers that do not support partial specialisation, no benefit will occur from using call_traits: the call_traits defined types will always be the same as the existing practice in this case.
If T is an array type, then call_traits defines value_type
as a "pointer to type" rather than an "array of type" (requires partial specialisation). Note that arrays can not normally be copied so instead this will result in storing a "pointer to an array" rather than the array itself, this may or may not be a good thing depending upon the usage of the class in question (in other words take care!).
If T is a small built in type or a pointer, thenparam_type
is defined asT const
, instead ofT const&
. This can improve the ability of the compiler to optimise loops in the body of the function if they depend upon the passed parameter, the semantics of the passed parameter is otherwise unchanged (requires partial specialisation).
Copy constructability
The following table defines which call_traits types can always be copy-constructed from which other types, those entries marked with a '?' are true only if T is itself copy constructable:
If T is an assignable type the following types are assignments are possible:
I think if there's no partial-specialization you can still use call_traits::value_type with reference types.
Example 1:
The following class is a model for std::pair and is taken from the call_traits_test.cpp file, it shows how each of the available call_traits typedefs may be used:
What does "is a model for std::pair" mean? This example does not have enough (correct?) motivating commentary to make it useful.
Now consider what happens in the relatively common case that the functor takes it's
No apostrophe in the possessive form of "its".
Example 3 (the make_pair problem):
If we pass the name of an array as one (or both) arguments to
std::make_pair
, then template argument deduction deduces the passed parameter as "const reference to array of T", this also applies to string literals (which are really array literals). Consequently instead of returning a pair of pointers, it tries to return a pair of arrays, and since an array type is not copy-constructable the code fails to compile. One solution is to explicitly cast the arguments to make_pair to pointers, but call_traits provides a better (i.e. automatic) solution:
Add "and one that works safely even in generic code where the cast might do the wrong thing"
template <bool opt>
struct filler
{
template <typename I, typename T>
static void do_fill(I first, I last, typename boost::call_traits<T>::param_type val);
};
template <bool b>
template <typename I, typename T>
void filler<b>::do_fill(I first, I last, typename boost::call_traits<T>::param_type val)
{
while(first != last)
{
*first = val;
++first;
}
}
I'm all for out-of-class function bodies, but I think in this case it just harms readability of the example.
Rational
The following notes are intended to briefly describe the rational behind choices made in call_traits.
I think the word you want here is "rationale".
All user-defined types follow "existing practice" and need no comment.
Small built-in types differ from existing practice only in the param_type typedef. In this case passing "T const" is compatible with existing practice, but may improve performance in some cases (see Example 4), in any case this should never be any worse than existing practice.
I guess you should say "small built-in non-reference types". An int& is a small built-in type, right?
Pointers follow the same rational as small built-in types.
For reference types the rational follows Example 2 - references to references are not allowed, so the call_traits members must be defined such that these problems do not occur. There is a proposal to modify the language such that "a reference to a reference is a reference" (issue #106, submitted by Bjarne Stroustrup), call_traits mirrors that proposal.
I wouldn't say "mirrors". You might want to try to find a better word. Also, why is call_traits<const int&>::param_type "const int&" and not simply "const int"? Wouldn't that be more efficient and probably otherwise equivalent?
For array types, a function that takes an array as an argument will degrade the array type to a pointer type, call_traits makes that conversion explicit. For value_type (return by value), again only a pointer may be returned, not a copy of the whole array, and again call_traits makes the conversion explicit. The value_type member is also useful whenever an array must be explicitly degraded to a pointer - Example 3 provides the test case.
Need a period, semicolon or colon after "degrade the array type to a pointer type". I'm not sure what "makes the conversion explicit" means in this context. Is that an advantage? Maybe what you're trying to say is "forces that degrading to happen where it might not otherwise, in cases of deduced template type parameters"?
-Dave