4 min read

Template Terminology

Intro

In the Spring of 2019 I started working on a mlpack automatically generated binding to R or Rcpp to be more precise. Both projects utilize a very powerful, yet complicated C++ language feature called templates. C++ is a statically typed language meaning your code is type checked at compile-time versus run-time in the case of R. In theory this language feature should allow the programmer to abstract away from concrete algorithms, to generic algorithms that operate on different data types and structures. However, in practice this can be quite difficult depending on the compiler and which C++ standard you’re working with. This initial post aims to be the first of many on templates and help clarify the technical jargon surrounding templates.

“Template Class” or “Class Template”?

According to the C++ standard structs, classes and unions are called class types . Class includes the previous mentioned class types preceded by the keywords class and struct , but not unions.

A lot of confusion surrounds the terminology of a class that is a template.

  • class template i.e. class that happens to be a template. Or parametized representation of a family of classes.
  • template class has the following uses
    • synonym for class template.
    • refer to classes generated from templates.
    • refer to named classes with a template-id.

As a result of the vagueness around the properties of a template class you should avoid use of the term.

Correspondingly, use function template and member function template as a good rule of thumb.

Instantiation and Specialization

Template insantiation is a procedure for creating a class, function, or member function from a template by passing values for its arguments. The resulting entity is a specialization. Alternatively, the programmer can pass different arguments to the declaration e.g.

template <typename T1, typename T2> // primary class template 
class AClass{
...
};


template<> // explicit specialization
class AClass<std::vector, int> {
...
};

template <typename T> // partial specialization 
class AClass<T,T> { 
...
};

template <typename T> // partial specialization
class AClass<bool,T>{
...
};

Definitions versus Declarations

According to the C++ standard a declaration is a C++ construct that introduces a name into a scope. All of the information or the implementation of that name are not necessary for a valid declaration e.g. :

class D; // a declaration of D as a class
void h (double g); // a declaration of h() as a function and g as a named parameter
extern int j; // a declaration of j as a variable

In contrast goto labels and macro definitions are not considered declarations in C++.

Declarations become definitions when the underlying implementation of their stucture are present, with variables this means when their storage space is allocated in memory. Classes and functions make this transition when a brace-enclosed body are present. e.g. :

class D{}; // definition and declaration of class D
void h(double g) { // definition and declaration of function h()
    std::cout << g << std::endl;

}

extern int j = 10; // initializer makes this a definition for j

int j; // global var declarations not preceded by extern qualifies as a definition
  • declaration of function template

    template <typename T>
    void funky (T);
    
  • definition of class template

    template <typename T>
    class B {};
    

The One-Definition Rule

The C++ language definition places a number of rules and constraints on redeclarations. These constraints are better known as the one-definition rule or ODR. ODR basics are as follows:

  • Noninline functions and member functions, as well as global variables and static data members should be defined only once across a whole program.
  • Class types and inline functions should be defined at most once per translation unit, and all these definitions should be identical.

The result of preprocessing a source file including what is named by a #include directive is a translation unit. Anything generated by a template can be thought of as linkable entity.

Template Parameters versus Template Arguments

The two following code chunks are roughly equivalent.

template <typename T, int J>
class ArrayNestClass {
 public:
   T array[J];
};

class BoolArrayNestClass {
 public:
  bool array[4];
};

Upon substituting in the values bool and 4 for the parameters T and J the former and the latter are the same.

ArrayNestClass<bool,4>

The template arguments fall within the angled brackets in the above syntax. The presence of the template name followed by arguments in angle brackets is a template-id. The template can be used as follows.

int main()
{
    ArrayNestClass<bool,4> ap;
    ap.array[1] = true;
}

A simple way of distinguishing between template parameters and template arguments is you “pass arguments to become parameters”.

Summary

  • Prefer the usage of terms like class template , function template, and member function template when talking about templates.
  • Templates can be specialized by passing arguments to it’s declarations.
  • Declarations introduce a name into a C++ scope.
  • Definitions of classes and functions require a brace-enclosed body.
  • Follow ODR the compiler will complain.
  • Template arguments are passed by substitution or value.
  • Template arguments can be more than just names even template parameters
  • Templates can be constructed out of other templates.

References

Vandvoorde, David, Josuttis, Nicolai. 2002 C++ Templates The Complete Guide