mirror of
https://github.com/boostorg/tti.git
synced 2026-01-19 16:52:12 +00:00
99 lines
6.1 KiB
Plaintext
99 lines
6.1 KiB
Plaintext
[/
|
|
(C) Copyright Edward Diener 2011,2019
|
|
Distributed under the Boost Software License, Version 1.0.
|
|
(See accompanying file LICENSE_1_0.txt or copy at
|
|
http://www.boost.org/LICENSE_1_0.txt).
|
|
]
|
|
|
|
[section:tti_function_templates Introspecting function templates technique]
|
|
[#sectti_function_templates]
|
|
|
|
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.
|
|
|
|
[heading 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.
|
|
|
|
[endsect]
|