Chapter Contents

Previous

Next
Templates

Function Templates

The C++ language allows function templates in addition to class templates. Function templates provide the ability to create generic functions that are parameterized on types and constant values. The terms function template and template function are sometimes used interchangeably. Strictly, however, a function template is a declaration that specifies a family of overloaded functions. The declaration of a member function in a class template also is considered a function template. An instance of the family of overloaded functions associated with a function template is generated by specializing the template, which involves filling in particular types and values for the template parameters. A template function, then, is just an instance of a function template where particular values for all the template parameters have been determined.

The SAS/C C++ Development System supports function templates with nontype parameters. Refer to Template Parameters for a description of nontype parameters. You can use nontype parameters to declare the template parameters and return types in a function template declaration. An example follows:

template <int SZ> class Bitvect;

template <int SZ1, int SZ2>
Bitvect<SZ1+SZ2> concat( const Bitvect<SZ1>& b1,
                 const Bitvect<SZ1>& b2 );

Nonmember function templates cannot have default arguments.


Overloading Function Templates

Function templates and ordinary nontemplate functions having the same name are not related. However, C++ allows for a function template to be overloaded with other function templates or nontemplate functions. During call overload resolution, each function template corresponding to the called name creates at most one candidate specialization of the template. The specialization is created by determining types and values for the template parameters through template argument deduction.

Specializations of a function template participate like ordinary functions in the overload resolution process. Once all functions for which there are better matches are eliminated, only the nontemplate functions that are left over are considered. Therefore, a function template is chosen only if it is a better match than any of the nontemplate functions.


Deducing Arguments

The template arguments for a member function of a template class are the actual template arguments for the template class. Otherwise, the template arguments are determined by deduction from the function parameter types.

Template argument deduction determines template parameter values by comparing each function parameter of the function template with the corresponding arguments of the call. Arguments that are not dependent on unspecified template parameters are matched to parameters exactly as they would be in normal function arguments. Otherwise, types and values are chosen for the template parameters which, when substituted in each function template parameter type, will match the corresponding argument type after trivial argument conversions. The trivial conversions performed on template arguments are

In certain cases, template parameters cannot be deduced. For example, a template parameter used in the scope of a qualified name cannot be deduced:

template <class T>
void f( typename T::Z* ); // T not deducible

Template parameters used in subexpressions in a template function declaration cannot be deduced either. However, parameters that are used directly as array bounds and class template arguments are deducible. Several examples follow:

template <int sz>
void f1( int (*arrayPtr)[sz] );     // deducible

template <int sz>
void f2( int (*arrayPtr)[sz+1] ); // sz not
                                  // deducible

template <class T, int SZ> class Vect;

template <class T, int sz>
void f3( Vect<T, sz>& v );    // deducible

template <class T, int sz>
void f4( Vect<T, sz+1>& v );    // sz not deducible

template <class T>
void f5( Vect<T, 8/sizeof(T) >& v ); // T not
                                 // deducible

template <class T, int sz>
void f6( Vect<T*, sz >& v );  // deducible

Note:    The major array bound of an array parameter to a function is ignored when deducing the parameter type:

template <int size>
void f7( int a[size][4] ); // size not
                         // deducible,
              // same as "int (*a)[4]"

  [cautionend]

Because the type of a function template that uses template parameters in subexpressions is not readily available, any redeclaration of the function template must match textually, at the token level, with the exception of template parameters which can be renamed. For example:

template <int N>
void f8( int(*ap) [N+1]);

template <int U>
void f8( int(*ap) [U+1]); // redeclaration -
                // template parameters renamed


Specifying Arguments

Template arguments for nonmember template functions may be specified in the form:

function_template_name< optional_template_args >;

The function template name is followed by a possibly empty ( < > ) template argument list.

Explicit template argument list specifications for function templates are an ANSI/ISO extension. They are used as a function name in expressions and in explicit specialization and instantiation declarations when the template has parameters that cannot be deduced from the context. For example, if a function template has template parameters that are not deducible, then an explicit template argument list containing actual values for those parameters must be used to call it.

Effectively, explicit template arguments are used to select a subset of the function templates that match the specified arguments. Then the parameters that correspond to the specified arguments are fixed. For example:

template <class T, class U>
inline T implicit_cast( U u ) { return u; }

This example produces a function that will perform an implicit conversion to the specified type, therefore avoiding a cast that could allow unsafe conversions:

void f( double );
void f( int );

template <class T>
void callit( T t )
{
   // call f( double )
   f( implicit_cast<double>( t ) );
}

Not all the arguments for the function template need to be specified when using an explicit template argument list. The specified arguments are substituted for the corresponding parameters in the declared type of each matching template. Any template arguments not specified are deduced in the normal manner. Function arguments for which all template parameters are specified are treated like normal function arguments for overload resolution purposes. For example:

template <class T>
inline T Max( T x, T y )
 { return (x > y ) ? x : y; }

int compare( int i, char c )
{
    // Calling Max( i, c ) would fail because
    // the argument types differ too much,
    // and the template parameter cannot
    // be deduced.  But you can explicitly
    // specify the type.
    Max<int>( i, c );  // OK, calls Max(int, int)
}

As an alternative to explicit template argument specification, older C++ implementations allow a construct called a guiding declaration. A guiding declaration uses an ordinary declaration to specify a specialization of a function template. A guiding declaration is used to avoid the same deduction problem illustrated in the previous example.

template <class T>
inline T Max( T x, T y )
 { return (x > y ) ? x : y; }

int Max( int, int );  // guiding declaration

int compare( int i, char c )
{
   // Calling Max( i, c ) would fail without
   // the guiding declaration because the
   // argument types differ too much.
   Max( i, c );  // OK, calls Max(int, int)
}

When the tmplfunc translator option is specified, nontemplate functions are distinct from template specializations. Therefore, guiding declarations are not recognized. In such cases, inline functions can be used in place of the guiding declaration:

template <class T>
inline T Max( T x, T y )
 { return (x > y ) ? x : y; }

// forwarding declaration
inline int Max( int x, int y )
{  return Max<>( x, y ); }  // call the template
                            // version

int compare( int i, char c )
{
    // Calling Max( i, c ) would fail without
    // the forwarding declaration because the
    // argument types differ too much.
    Max( i, c );  // OK, calls Max(int, int)    }

See Option Descriptions for a full description of the tmplfunc option.


Function Template Signatures

Functions with normal linkage conventions (not extern "C" ) encode information about their parameter types into their linkage name. For specializations of function templates, this linkage information potentially includes the template arguments also. When the template arguments are included, components such as COOL will print the name including the template arguments using the function name followed by the actual template arguments.

The ANSI/ISO C++ draft treats specializations of function templates as distinct objects from non-template declarations with the same name and type. Effectively, the linkage names of template specializations are different from non-template linkage names. Older C++ compilers treat non-template declarations that match template specializations as the same object. Therefore, the same linkage name is used.

By default, the SAS/C C++ Development System uses the nontemplate linkage name for specializations of normally deducible function templates for compatibility with older code. Functions which are not deducible (see message LSCT628 in SAS/C Software Diagnostic Messages), which older compilers treat as erroneous, always include the template parameters in their linkage. With the tmplfunc option, the linkage names of function template specializations will be made distinct from nontemplate functions, by including the template arguments for the specialization in the linkage name.


Other Template Signatures

When the translator or other tools refer to names with C++ linkage whose scope or type depends on templates, the name printed out contains template argument lists. For the most part, the interpretation of these template arguments should be obvious. These tools have incomplete information about the types and definitions involved, so some special cases are worth noting:

In the latter two cases, there may be no unique C++ expression that generates the given value, so a standard form was chosen.


Chapter Contents

Previous

Next

Top of Page

Copyright © 2001 by SAS Institute Inc., Cary, NC, USA. All rights reserved.