Boost logo

Boost :

From: David Abrahams (abrahams_at_[hidden])
Date: 2000-07-08 15:52:54


----- Original Message -----
From: "John Maddock" <John_Maddock_at_[hidden]>

> The rewritten docs are in the vault, and have been for a while, and do make
> it quite clear (I hope!) what is supported on given compilers along with
> copious usage examples - I did ask for feedback on these but none has been
> forthcoming so far - want to take it on before Beman applies the updates to
> boost?

OK:

First let me say that the docs are very impressive in their overall completeness

    In each case if your existing practice is to use the type defined on the left, then replace it with the call_traits defined type on the right. The purpose of call_traits is to ensure that problems like "references to references" never occur, and that parameters are passed in the most efficient manner possible (see examples).
It might be clearer if you swapped the two sentences above.

  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.
That pretty much covers what I was looking for.

In the first table, why does note 1 appear with call_traits<T>::value_type? Regardless of partial-specialisation, you can always return T and avoid references-to-references. It seems like "(requires partial specialisation)" is meaningless in this particular case. Also, I have nothing against the British spelling, but the standard defines the term with a 'z', so it's more precise (I think) to use the same spelling. I think the standard also writes "copy-constructible" where you are writing "copy-constructable".

Note 2 says:

  a.. 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!).
I think the word "storing" is misleading here; it would be better if you just removed it. The comma after "itself" should be a period. What "class in question?" Maybe you should just say "depending on your needs".

  If T is a small built in type or a pointer, then param_type is defined as T const, instead of T 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).
This doesn't agree with the 3rd table which says that param_type<int> is just plain int (not "int const"). Also, it would help if you were consistent about the placement of const. In other places you write "const int".

  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:

I think you want to say "...are true if and only if T is..."

  If T is an assignable type the following types are assignments are possible:
"are" should be "of"

  Examples
  The following table shows the effect that call_traits has on various types, the table assumes that the compiler supports partial specialisation: if it doesn't then all types behave in the same way as the entry for "myclass", and call_traits can not be used with reference or array types.

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



Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk