Boost C++ Libraries

...one of the most highly regarded and expertly designed C++ library projects in the world. Herb Sutter and Andrei Alexandrescu, C++ Coding Standards

PrevUpHomeNext

Introspecting function templates technique

Function templates, like functions, can be entities within a user-defined type. Just as functions within a user-defined type can be member functions or static member functions, function templates within a user-defined type can be member function templates or static member function templates. In this respect function templates are related to functions. Function templates represent a family of possible functions. In this respect they are similar to class templates, which represent a family of possible class types.

The technique for introspecting class templates in the TTI library is taken from the implementation of the technique in the Boost MPL library. In the case of BOOST_TTI_HAS_TEMPLATE using the template type parameters form it directly uses the Boost MPL library functionality while in the case of BOOST_TTI_HAS_TEMPLATE using the specific form it replicates much of the technique in the Boost MPL library. Either technique for introspecting class templates depends directly on the fact that in C++ we can pass a template as a parameter to another template using what is called a "template template" parameter type.

One obvious thing about a template template parameter type is that it is a class template. The fact that we can pass class templates as a template parameter but not function templates as a template parameter is the major factor why there is no equivalent method for introspecting a function template signature at compile time as there is for introspecting class templates signature.

Introspection using an instantiated function template

Although there is no way to introspect for a function template signature in TTI, there is an alternate way of introspecting a function template. It is possible to check whether some particular instantiation of a nested function template exists at compile-time without generating a compiler error, as long as all the lower level indidual types in that instantiation exist at the time introspection of a function template occurs. In plainer C++ terms we call the instantiation of a function template "calling ( or invoking ) the function template". Although checking whether some particular instantiation of a nested function template exists at compile-time does not prove that the nested function template itself has a particular signature, since the instantiation itself may fail even when the nested function template does exist, it provides a viable way of introspecting function templates because the vast majority of function templates are designed to accept any type(s) and avoid compile time failure. Also when we introspect using a function template instantiation for a nested function template we are replicating how function templates are actually used in C++.

To see how this works in general in the TTI library I will give an example of a nested function template in a user-defined type.

struct AType
  {
  template<class X,class Y,class Z> double AFuncTemplate(X x,Y * y,Z & z)
    { ...some code using x,y,z; return 0.0; }
  };

The code shows a member function template within a user-defined struct called AType. Ideally what we would like to do is to be able to verify that the function template signature of template<class X,class Y,class Z> double AFuncTemplate(X,Y *,Z &) exists within the AType type, but we can not do that in TTI. If we were to call AFuncTemplate from within some functionality within the AType type, we would substitute some arguments for X,Y *,Z & and the C++ compiler would be able to figure out the types for X, Y, and Z and create a function to be called.

If we look at this in terms of compile time programming ( aka template metaprogramming ) what we are really interested in is whether there is a function template called AFuncTemplate within a type called AType which can be invoked with the X, Y, and Z types as some set of types which are equivalent to calling AFuncTemplate with some set of arguments. Let's suppose we want to call AFuncTemplate with an int value as the first argument, long * as the second argument, and a bool & as the third argument. In TTI introspection terms for a function template what we therefore are going to do is to check if we can instantiate the function template as:

double AFuncTemplate<int,long,bool>(int,long *,bool &)

This is the form of a single possible instantiation of function template AFuncTemplate. When it is subsequently explained how to use an instantiation of a function template to check if an inner function template exists, this is what we mean. The instantiation itself does not exist when we introspect a function template but all the parts of our instantiation signature are used in the process of introspection. It should be realized that we could use any combination of valid types or values to create our theoretical instantiation of a given function template, as long as those type and/or values produces a valid callable function which does not contain compile time errors.

The actual types and/or values we use in an instantiation of a function template we introspect must be declared when we do the introspection. For built-in types this is always the case. If we use instead, for whatever reason, a user-defined type in a given instantiation, that type must be declared when we invoke the metafunction which does the introspection.

Further areas of the documentation will explain in its place how we use an instantiation of a function template to introspect respectively a member function template, a static member function template, or any inner function template. The technique we use is very similar to the way we introspect any nested entity, but instead of looking for a signature that declares that nested entity, with function templates we look for a signature representing some instantiation of the function template.


PrevUpHomeNext