Topic: Implementing type functions


Author: "Kevin S. Van Horn" <ksvhsoft@xmission.com>
Date: 1997/08/21
Raw View
Partial specialization of templates, together with the idea of a traits
class, gives us a way of implementing "type functions" in C++, i.e.,
"functions" (actually class templates) that take one or more types as
input (template arguments) and produce one or more types as output
(typedefs of the resulting class).  Here's an example of one such type
function I've found useful, taken from the collection of free software
components on my website (see my sig below).

For any type T, cvrp_traits<T> is a traits class that provides typedefs
for various classes related to T.  Here are the typedefs it provides:

1. p_value_type.  The "plain" type on which T is based, gotten by
turning references into the referenced type, and then removing any
cv-qualifiers (const or volatile qualifiers).  For example, if T is
    int const &
then p_value_type is int.

2. v_value_type, c_value_type, cv_value_type.  Synonyms for p_value_type
volatile, p_value_type const, and p_value_type const volatile,
respectively.

3. p_reference.  Synonym for p_value_type &.  Not defined when T is
void.

4. v_reference, c_reference, cv_reference.  Synonyms for v_value_type &,
c_value_type &, and cv_value_type &, respectively.  Not defined when T
is void.

5. p_pointer.  Synonym for p_value_type *.

6. v_pointer, c_pointer, cv_pointer.  Synonyms for v_value_type *,
c_value_type *, and cv_value_type *, respectively.

7. reference. One of p_reference, v_reference, c_reference, or
cv_reference, chosen so as to have the same const or volatile qualifiers
as T (or the referenced type, if T is a reference type.)  For
example,
* if T is int or int &, then reference is int &;
* if T is int const or int const &, then reference is int const &.

8. pointer. One of p_pointer, v_pointer, c_pointer, or cv_pointer,
chosen so as to have the same const or volatile qualifiers as T
(or the referenced type, if T is a reference type.)  For example,
* if T is int or int &, then pointer is int *;
* if T is int const or int const &, then pointer is int const *.

9. strip_cvqual.  Same as T with any outermost const or volatile
qualifiers stripped off.  For example,
* if T is int or int const, then strip_cvqual is int;
* if T is int const &, then strip_cvqual is the same as T, since the
const qualifier applies only to the referenced type, and not to the
reference itself.

The cvrp_traits<> class template is useful when you are doing generic
programming.  For example, suppose you're writing a function that is
supposed to be able to take an arbitrary function pointer as input, i.e.
it look something like

  template <class R, class A>
  void foo(R (*f)(A))
  { ... }

You may want a temporary variable of a type suitable for passing to f as
an argument.  But A may not be a "plain" type -- it may be a reference
type, and it may have cv-qualifiers.  So you use cvrp_traits<>:

  typedef typename cvrp_traits<A>::p_value_type Ap;
  Ap tmp;
  ...

Here is the code for cvrp_traits<>:

#if 0
Copyright (C) 1997 by Kevin S. Van Horn.  You may freely use and modify
this software, subject to the following restrictions:
  (1) This copyright notice must remain in the source, unchanged.
  (2) You are NOT allowed to redistribute this software in any form.
The current version of this software may be obtained at
http://www.xmission.com/~ksvhsoft/ by following the software components
link.  NOTE: This software is provided without warranty of any kind.
#endif

template <class T>
struct cvrp_traits {
  typedef T                    p_value_type;  // plain
  typedef T volatile           v_value_type;
  typedef T const              c_value_type;
  typedef T const volatile     cv_value_type;

  typedef p_value_type &       p_reference;  // plain
  typedef v_value_type &       v_reference;
  typedef c_value_type &       c_reference;
  typedef cv_value_type  &     cv_reference;

  typedef p_value_type *       p_pointer;  // plain
  typedef v_value_type *       v_pointer;
  typedef c_value_type *       c_pointer;
  typedef cv_value_type *      cv_pointer;

  typedef p_reference          reference;
  typedef p_pointer            pointer;
  typedef T                    strip_cvqual;
};

template <>
struct cvrp_traits<void> {
  typedef void                 p_value_type;  // plain
  typedef void volatile        v_value_type;
  typedef void const           c_value_type;
  typedef void const volatile  cv_value_type;

  typedef p_value_type *       p_pointer;  // plain
  typedef v_value_type *       v_pointer;
  typedef c_value_type *       c_pointer;
  typedef cv_value_type *      cv_pointer;

  typedef p_pointer            pointer;
  typedef void                 strip_cvqual;
};

template <class T>
struct cvrp_traits<T const> : public cvrp_traits<T> {
  typedef typename cvrp_traits<T>::c_reference reference;
  typedef typename cvrp_traits<T>::c_pointer   pointer;
  typedef T strip_cvqual;
};

template <class T>
struct cvrp_traits<T volatile> : public cvrp_traits<T> {
  typedef typename cvrp_traits<T>::v_reference reference;
  typedef typename cvrp_traits<T>::v_pointer   pointer;
  typedef T strip_cvqual;
};

template <class T>
struct cvrp_traits<T const volatile> : public cvrp_traits<T> {
  typedef typename cvrp_traits<T>::cv_reference reference;
  typedef typename cvrp_traits<T>::cv_pointer   pointer;
  typedef T strip_cvqual;
};

template <class T>
struct cvrp_traits<T &> : public cvrp_traits<T> {
  typedef T & strip_cvqual;
};

-----------------------------------------------------------------
Kevin S. Van Horn            | ksvhsoft@xmission.com
KSVH Software and Consulting | http://www.xmission.com/~ksvhsoft/

      [ Send an empty e-mail to c++-help@netlab.cs.rpi.edu for info ]
      [ about comp.lang.c++.moderated. First time posters: do this! ]